mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-26 14:19:24 +00:00
Design improvemtns to automation customisation
This commit is contained in:
parent
f7a4aaa766
commit
d835dbd510
@ -30,6 +30,8 @@ export interface TextInputProps {
|
|||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
/** Accessibility label */
|
/** Accessibility label */
|
||||||
'aria-label'?: string;
|
'aria-label'?: string;
|
||||||
|
/** Focus event handler */
|
||||||
|
onFocus?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(({
|
export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(({
|
||||||
@ -45,6 +47,7 @@ export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(({
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
readOnly = false,
|
readOnly = false,
|
||||||
'aria-label': ariaLabel,
|
'aria-label': ariaLabel,
|
||||||
|
onFocus,
|
||||||
...props
|
...props
|
||||||
}, ref) => {
|
}, ref) => {
|
||||||
const { colorScheme } = useMantineColorScheme();
|
const { colorScheme } = useMantineColorScheme();
|
||||||
@ -62,7 +65,7 @@ export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(({
|
|||||||
return (
|
return (
|
||||||
<div className={`${styles.container} ${className}`} style={style}>
|
<div className={`${styles.container} ${className}`} style={style}>
|
||||||
{icon && (
|
{icon && (
|
||||||
<span
|
<span
|
||||||
className={styles.icon}
|
className={styles.icon}
|
||||||
style={{ color: colorScheme === 'dark' ? '#FFFFFF' : '#6B7382' }}
|
style={{ color: colorScheme === 'dark' ? '#FFFFFF' : '#6B7382' }}
|
||||||
>
|
>
|
||||||
@ -80,6 +83,7 @@ export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(({
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
aria-label={ariaLabel}
|
aria-label={ariaLabel}
|
||||||
|
onFocus={onFocus}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: colorScheme === 'dark' ? '#4B525A' : '#FFFFFF',
|
backgroundColor: colorScheme === 'dark' ? '#4B525A' : '#FFFFFF',
|
||||||
color: colorScheme === 'dark' ? '#FFFFFF' : '#6B7382',
|
color: colorScheme === 'dark' ? '#FFFFFF' : '#6B7382',
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from "react-i18next";
|
||||||
import { Text, Stack, Group, ActionIcon } from '@mantine/core';
|
import { Text, Stack, Group, ActionIcon } from "@mantine/core";
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import SettingsIcon from "@mui/icons-material/Settings";
|
||||||
import SettingsIcon from '@mui/icons-material/Settings';
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import AddCircleOutline from "@mui/icons-material/AddCircleOutline";
|
||||||
import AddCircleOutline from '@mui/icons-material/AddCircleOutline';
|
import { AutomationTool } from "../../../types/automation";
|
||||||
import { AutomationTool } from '../../../types/automation';
|
import { ToolRegistryEntry } from "../../../data/toolsTaxonomy";
|
||||||
import { ToolRegistryEntry } from '../../../data/toolsTaxonomy';
|
import ToolSelector from "./ToolSelector";
|
||||||
import ToolSelector from './ToolSelector';
|
import AutomationEntry from "./AutomationEntry";
|
||||||
import AutomationEntry from './AutomationEntry';
|
|
||||||
|
|
||||||
interface ToolListProps {
|
interface ToolListProps {
|
||||||
tools: AutomationTool[];
|
tools: AutomationTool[];
|
||||||
@ -29,35 +28,39 @@ export default function ToolList({
|
|||||||
onToolConfigure,
|
onToolConfigure,
|
||||||
onToolAdd,
|
onToolAdd,
|
||||||
getToolName,
|
getToolName,
|
||||||
getToolDefaultParameters
|
getToolDefaultParameters,
|
||||||
}: ToolListProps) {
|
}: ToolListProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleToolSelect = (index: number, newOperation: string) => {
|
const handleToolSelect = (index: number, newOperation: string) => {
|
||||||
const defaultParams = getToolDefaultParameters(newOperation);
|
const defaultParams = getToolDefaultParameters(newOperation);
|
||||||
|
|
||||||
onToolUpdate(index, {
|
onToolUpdate(index, {
|
||||||
operation: newOperation,
|
operation: newOperation,
|
||||||
name: getToolName(newOperation),
|
name: getToolName(newOperation),
|
||||||
configured: false,
|
configured: false,
|
||||||
parameters: defaultParams
|
parameters: defaultParams,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Text size="sm" fw={500} mb="xs" style={{ color: 'var(--mantine-color-text)' }}>
|
<Text size="sm" fw={500} mb="xs" style={{ color: "var(--mantine-color-text)" }}>
|
||||||
{t('automate.creation.tools.selected', 'Selected Tools')} ({tools.length})
|
{t("automate.creation.tools.selected", "Selected Tools")} ({tools.length})
|
||||||
</Text>
|
</Text>
|
||||||
<Stack gap="0">
|
<Stack gap="0">
|
||||||
{tools.map((tool, index) => (
|
{tools.map((tool, index) => (
|
||||||
<React.Fragment key={tool.id}>
|
<React.Fragment key={tool.id}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
border: '1px solid var(--mantine-color-gray-2)',
|
border: "1px solid var(--mantine-color-gray-2)",
|
||||||
borderRadius: 'var(--mantine-radius-sm)',
|
borderRadius: tool.operation && !tool.configured
|
||||||
position: 'relative',
|
? "var(--mantine-radius-lg) var(--mantine-radius-lg) 0 0"
|
||||||
padding: 'var(--mantine-spacing-xs)'
|
: "var(--mantine-radius-lg)",
|
||||||
|
backgroundColor: "var(--mantine-color-gray-2)",
|
||||||
|
position: "relative",
|
||||||
|
padding: "var(--mantine-spacing-xs)",
|
||||||
|
borderBottomWidth: tool.operation && !tool.configured ? "0" : "1px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Delete X in top right */}
|
{/* Delete X in top right */}
|
||||||
@ -65,26 +68,26 @@ export default function ToolList({
|
|||||||
variant="subtle"
|
variant="subtle"
|
||||||
size="xs"
|
size="xs"
|
||||||
onClick={() => onToolRemove(index)}
|
onClick={() => onToolRemove(index)}
|
||||||
title={t('automate.creation.tools.remove', 'Remove tool')}
|
title={t("automate.creation.tools.remove", "Remove tool")}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
top: '4px',
|
top: "4px",
|
||||||
right: '4px',
|
right: "4px",
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
color: 'var(--mantine-color-gray-6)'
|
color: "var(--mantine-color-gray-6)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CloseIcon style={{ fontSize: 12 }} />
|
<CloseIcon style={{ fontSize: 16 }} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
|
||||||
<div style={{ paddingRight: '1.25rem' }}>
|
<div style={{ paddingRight: "1.25rem" }}>
|
||||||
{/* Tool Selection Dropdown with inline settings cog */}
|
{/* Tool Selection Dropdown with inline settings cog */}
|
||||||
<Group gap="xs" align="center" wrap="nowrap">
|
<Group gap="xs" align="center" wrap="nowrap">
|
||||||
<div style={{ flex: 1, minWidth: 0 }}>
|
<div style={{ flex: 1, minWidth: 0 }}>
|
||||||
<ToolSelector
|
<ToolSelector
|
||||||
key={`tool-selector-${tool.id}`}
|
key={`tool-selector-${tool.id}`}
|
||||||
onSelect={(newOperation) => handleToolSelect(index, newOperation)}
|
onSelect={(newOperation) => handleToolSelect(index, newOperation)}
|
||||||
excludeTools={['automate']}
|
excludeTools={["automate"]}
|
||||||
toolRegistry={toolRegistry}
|
toolRegistry={toolRegistry}
|
||||||
selectedValue={tool.operation}
|
selectedValue={tool.operation}
|
||||||
placeholder={tool.name}
|
placeholder={tool.name}
|
||||||
@ -97,26 +100,37 @@ export default function ToolList({
|
|||||||
variant="subtle"
|
variant="subtle"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => onToolConfigure(index)}
|
onClick={() => onToolConfigure(index)}
|
||||||
title={t('automate.creation.tools.configure', 'Configure tool')}
|
title={t("automate.creation.tools.configure", "Configure tool")}
|
||||||
style={{ color: 'var(--mantine-color-gray-6)' }}
|
style={{ color: "var(--mantine-color-gray-6)" }}
|
||||||
>
|
>
|
||||||
<SettingsIcon style={{ fontSize: 16 }} />
|
<SettingsIcon style={{ fontSize: 16 }} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
)}
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
{/* Configuration status underneath */}
|
|
||||||
{tool.operation && !tool.configured && (
|
|
||||||
<Text pl="md" size="xs" c="dimmed" mt="xs">
|
|
||||||
{t('automate.creation.tools.notConfigured', "! Not Configured")}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/* Configuration status underneath */}
|
||||||
|
{tool.operation && !tool.configured && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
border: "1px solid var(--mantine-color-gray-2)",
|
||||||
|
borderTop: "none",
|
||||||
|
borderRadius: "0 0 var(--mantine-radius-lg) var(--mantine-radius-lg)",
|
||||||
|
backgroundColor: "var(--active-bg)",
|
||||||
|
padding: "var(--mantine-spacing-xs)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text pl="md" size="xs" >
|
||||||
|
{t("automate.creation.tools.notConfigured", "! Not Configured")}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{index < tools.length - 1 && (
|
{index < tools.length - 1 && (
|
||||||
<div style={{ textAlign: 'center', padding: '8px 0' }}>
|
<div style={{ textAlign: "center", padding: "8px 0" }}>
|
||||||
<Text size="xs" c="dimmed">↓</Text>
|
<Text size="xs" c="dimmed">
|
||||||
|
↓
|
||||||
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
@ -124,19 +138,23 @@ export default function ToolList({
|
|||||||
|
|
||||||
{/* Arrow before Add Tool Button */}
|
{/* Arrow before Add Tool Button */}
|
||||||
{tools.length > 0 && (
|
{tools.length > 0 && (
|
||||||
<div style={{ textAlign: 'center', padding: '8px 0' }}>
|
<div style={{ textAlign: "center", padding: "8px 0" }}>
|
||||||
<Text size="xs" c="dimmed">↓</Text>
|
<Text size="xs" c="dimmed">
|
||||||
|
↓
|
||||||
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Add Tool Button */}
|
{/* Add Tool Button */}
|
||||||
<div style={{
|
<div
|
||||||
border: '1px solid var(--mantine-color-gray-2)',
|
style={{
|
||||||
borderRadius: 'var(--mantine-radius-sm)',
|
border: "1px solid var(--mantine-color-gray-2)",
|
||||||
overflow: 'hidden'
|
borderRadius: "var(--mantine-radius-sm)",
|
||||||
}}>
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<AutomationEntry
|
<AutomationEntry
|
||||||
title={t('automate.creation.tools.addTool', 'Add Tool')}
|
title={t("automate.creation.tools.addTool", "Add Tool")}
|
||||||
badgeIcon={AddCircleOutline}
|
badgeIcon={AddCircleOutline}
|
||||||
operations={[]}
|
operations={[]}
|
||||||
onClick={onToolAdd}
|
onClick={onToolAdd}
|
||||||
@ -146,4 +164,4 @@ export default function ToolList({
|
|||||||
</Stack>
|
</Stack>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { ToolRegistryEntry } from '../../../data/toolsTaxonomy';
|
|||||||
import { useToolSections } from '../../../hooks/useToolSections';
|
import { useToolSections } from '../../../hooks/useToolSections';
|
||||||
import { renderToolButtons } from '../shared/renderToolButtons';
|
import { renderToolButtons } from '../shared/renderToolButtons';
|
||||||
import ToolSearch from '../toolPicker/ToolSearch';
|
import ToolSearch from '../toolPicker/ToolSearch';
|
||||||
|
import ToolButton from '../toolPicker/ToolButton';
|
||||||
|
|
||||||
interface ToolSelectorProps {
|
interface ToolSelectorProps {
|
||||||
onSelect: (toolKey: string) => void;
|
onSelect: (toolKey: string) => void;
|
||||||
@ -72,7 +73,8 @@ export default function ToolSelector({
|
|||||||
if (baseFilteredTools.length > 0) {
|
if (baseFilteredTools.length > 0) {
|
||||||
return [{
|
return [{
|
||||||
name: 'All Tools',
|
name: 'All Tools',
|
||||||
tools: baseFilteredTools.map(([key, tool]) => ({ key, ...tool }))
|
subcategoryId: 'all' as any,
|
||||||
|
tools: baseFilteredTools.map(([key, tool]) => ({ id: key, tool }))
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
@ -140,26 +142,15 @@ export default function ToolSelector({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={containerRef} style={{ position: 'relative', width: '100%' }}>
|
<div ref={containerRef} className='rounded-xl'>
|
||||||
{/* Always show the target - either selected tool or search input */}
|
{/* Always show the target - either selected tool or search input */}
|
||||||
<div style={{ width: '100%' }}>
|
|
||||||
{selectedValue && toolRegistry[selectedValue] && !opened ? (
|
{selectedValue && toolRegistry[selectedValue] && !opened ? (
|
||||||
// Show selected tool in AutomationEntry style when tool is selected and dropdown closed
|
// Show selected tool in AutomationEntry style when tool is selected and dropdown closed
|
||||||
<div onClick={handleSearchFocus} style={{ cursor: 'pointer' }}>
|
<div onClick={handleSearchFocus} style={{ cursor: 'pointer',
|
||||||
<div style={{
|
borderRadius: "var(--mantine-radius-lg)" }}>
|
||||||
display: 'flex',
|
<ToolButton id='tool' tool={toolRegistry[selectedValue]} isSelected={false}
|
||||||
alignItems: 'center',
|
onSelect={()=>{}} rounded={true}></ToolButton>
|
||||||
gap: 'var(--mantine-spacing-sm)',
|
|
||||||
padding: '0 0.5rem',
|
|
||||||
borderRadius: 'var(--mantine-radius-sm)',
|
|
||||||
}}>
|
|
||||||
<div style={{ color: 'var(--mantine-color-text)', fontSize: '1.2rem' }}>
|
|
||||||
{toolRegistry[selectedValue].icon}
|
|
||||||
</div>
|
|
||||||
<Text size="sm" style={{ flex: 1, color: 'var(--mantine-color-text)' }}>
|
|
||||||
{toolRegistry[selectedValue].name}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
// Show search input when no tool selected OR when dropdown is opened
|
// Show search input when no tool selected OR when dropdown is opened
|
||||||
@ -167,14 +158,13 @@ export default function ToolSelector({
|
|||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={handleSearchChange}
|
onChange={handleSearchChange}
|
||||||
toolRegistry={filteredToolRegistry}
|
toolRegistry={filteredToolRegistry}
|
||||||
mode="filter"
|
mode="unstyled"
|
||||||
placeholder={getDisplayValue()}
|
placeholder={getDisplayValue()}
|
||||||
hideIcon={true}
|
hideIcon={true}
|
||||||
onFocus={handleInputFocus}
|
onFocus={handleInputFocus}
|
||||||
autoFocus={shouldAutoFocus}
|
autoFocus={shouldAutoFocus}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Custom dropdown */}
|
{/* Custom dropdown */}
|
||||||
{opened && (
|
{opened && (
|
||||||
|
@ -9,9 +9,10 @@ interface ToolButtonProps {
|
|||||||
tool: ToolRegistryEntry;
|
tool: ToolRegistryEntry;
|
||||||
isSelected: boolean;
|
isSelected: boolean;
|
||||||
onSelect: (id: string) => void;
|
onSelect: (id: string) => void;
|
||||||
|
rounded?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect }) => {
|
const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect, rounded = false }) => {
|
||||||
const handleClick = (id: string) => {
|
const handleClick = (id: string) => {
|
||||||
if (tool.link) {
|
if (tool.link) {
|
||||||
// Open external link in new tab
|
// Open external link in new tab
|
||||||
@ -33,7 +34,17 @@ const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect
|
|||||||
fullWidth
|
fullWidth
|
||||||
justify="flex-start"
|
justify="flex-start"
|
||||||
className="tool-button"
|
className="tool-button"
|
||||||
styles={{ root: { borderRadius: 0, color: "var(--tools-text-and-icon-color)" } }}
|
styles={{
|
||||||
|
root: {
|
||||||
|
borderRadius: rounded ? 'var(--mantine-radius-lg)' : 0,
|
||||||
|
color: "var(--tools-text-and-icon-color)",
|
||||||
|
...(rounded && {
|
||||||
|
'&:hover': {
|
||||||
|
borderRadius: 'var(--mantine-radius-lg)',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<FitText
|
<FitText
|
||||||
text={tool.name}
|
text={tool.name}
|
||||||
|
@ -76,4 +76,4 @@
|
|||||||
.search-input-container {
|
.search-input-container {
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,14 @@ import { Stack, Button, Text } from "@mantine/core";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ToolRegistryEntry } from "../../../data/toolsTaxonomy";
|
import { ToolRegistryEntry } from "../../../data/toolsTaxonomy";
|
||||||
import { TextInput } from "../../shared/TextInput";
|
import { TextInput } from "../../shared/TextInput";
|
||||||
import './ToolPicker.css';
|
import "./ToolPicker.css";
|
||||||
|
|
||||||
interface ToolSearchProps {
|
interface ToolSearchProps {
|
||||||
value: string;
|
value: string;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
toolRegistry: Readonly<Record<string, ToolRegistryEntry>>;
|
toolRegistry: Readonly<Record<string, ToolRegistryEntry>>;
|
||||||
onToolSelect?: (toolId: string) => void;
|
onToolSelect?: (toolId: string) => void;
|
||||||
mode: 'filter' | 'dropdown';
|
mode: "filter" | "dropdown" | "unstyled";
|
||||||
selectedToolKey?: string | null;
|
selectedToolKey?: string | null;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
hideIcon?: boolean;
|
hideIcon?: boolean;
|
||||||
@ -23,12 +23,12 @@ const ToolSearch = ({
|
|||||||
onChange,
|
onChange,
|
||||||
toolRegistry,
|
toolRegistry,
|
||||||
onToolSelect,
|
onToolSelect,
|
||||||
mode = 'filter',
|
mode = "filter",
|
||||||
selectedToolKey,
|
selectedToolKey,
|
||||||
placeholder,
|
placeholder,
|
||||||
hideIcon = false,
|
hideIcon = false,
|
||||||
onFocus,
|
onFocus,
|
||||||
autoFocus = false
|
autoFocus = false,
|
||||||
}: ToolSearchProps) => {
|
}: ToolSearchProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||||
@ -39,9 +39,10 @@ const ToolSearch = ({
|
|||||||
if (!value.trim()) return [];
|
if (!value.trim()) return [];
|
||||||
return Object.entries(toolRegistry)
|
return Object.entries(toolRegistry)
|
||||||
.filter(([id, tool]) => {
|
.filter(([id, tool]) => {
|
||||||
if (mode === 'dropdown' && id === selectedToolKey) return false;
|
if (mode === "dropdown" && id === selectedToolKey) return false;
|
||||||
return tool.name.toLowerCase().includes(value.toLowerCase()) ||
|
return (
|
||||||
tool.description.toLowerCase().includes(value.toLowerCase());
|
tool.name.toLowerCase().includes(value.toLowerCase()) || tool.description.toLowerCase().includes(value.toLowerCase())
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.slice(0, 6)
|
.slice(0, 6)
|
||||||
.map(([id, tool]) => ({ id, tool }));
|
.map(([id, tool]) => ({ id, tool }));
|
||||||
@ -49,7 +50,7 @@ const ToolSearch = ({
|
|||||||
|
|
||||||
const handleSearchChange = (searchValue: string) => {
|
const handleSearchChange = (searchValue: string) => {
|
||||||
onChange(searchValue);
|
onChange(searchValue);
|
||||||
if (mode === 'dropdown') {
|
if (mode === "dropdown") {
|
||||||
setDropdownOpen(searchValue.trim().length > 0 && filteredTools.length > 0);
|
setDropdownOpen(searchValue.trim().length > 0 && filteredTools.length > 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -65,8 +66,8 @@ const ToolSearch = ({
|
|||||||
setDropdownOpen(false);
|
setDropdownOpen(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
document.addEventListener('mousedown', handleClickOutside);
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Auto-focus the input when requested
|
// Auto-focus the input when requested
|
||||||
@ -79,7 +80,6 @@ const ToolSearch = ({
|
|||||||
}, [autoFocus]);
|
}, [autoFocus]);
|
||||||
|
|
||||||
const searchInput = (
|
const searchInput = (
|
||||||
<div className="search-input-container">
|
|
||||||
<TextInput
|
<TextInput
|
||||||
ref={searchRef}
|
ref={searchRef}
|
||||||
value={value}
|
value={value}
|
||||||
@ -87,36 +87,40 @@ const ToolSearch = ({
|
|||||||
placeholder={placeholder || t("toolPicker.searchPlaceholder", "Search tools...")}
|
placeholder={placeholder || t("toolPicker.searchPlaceholder", "Search tools...")}
|
||||||
icon={hideIcon ? undefined : <span className="material-symbols-rounded">search</span>}
|
icon={hideIcon ? undefined : <span className="material-symbols-rounded">search</span>}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
|
style={{padding: 0}}
|
||||||
onFocus={onFocus}
|
onFocus={onFocus}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (mode === 'filter') {
|
if (mode === "filter") {
|
||||||
|
return <div className="search-input-container">{searchInput}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode === "unstyled") {
|
||||||
return searchInput;
|
return searchInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={searchRef} style={{ position: 'relative' }}>
|
<div ref={searchRef} style={{ position: "relative" }}>
|
||||||
{searchInput}
|
{searchInput}
|
||||||
{dropdownOpen && filteredTools.length > 0 && (
|
{dropdownOpen && filteredTools.length > 0 && (
|
||||||
<div
|
<div
|
||||||
ref={dropdownRef}
|
ref={dropdownRef}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
top: '100%',
|
top: "100%",
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
zIndex: 1000,
|
zIndex: 1000,
|
||||||
backgroundColor: 'var(--mantine-color-body)',
|
backgroundColor: "var(--mantine-color-body)",
|
||||||
border: '1px solid var(--mantine-color-gray-3)',
|
border: "1px solid var(--mantine-color-gray-3)",
|
||||||
borderRadius: '6px',
|
borderRadius: "6px",
|
||||||
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
|
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
|
||||||
maxHeight: '300px',
|
maxHeight: "300px",
|
||||||
overflowY: 'auto'
|
overflowY: "auto",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack gap="xs" style={{ padding: '8px' }}>
|
<Stack gap="xs" style={{ padding: "8px" }}>
|
||||||
{filteredTools.map(({ id, tool }) => (
|
{filteredTools.map(({ id, tool }) => (
|
||||||
<Button
|
<Button
|
||||||
key={id}
|
key={id}
|
||||||
@ -125,22 +129,18 @@ const ToolSearch = ({
|
|||||||
onToolSelect && onToolSelect(id);
|
onToolSelect && onToolSelect(id);
|
||||||
setDropdownOpen(false);
|
setDropdownOpen(false);
|
||||||
}}
|
}}
|
||||||
leftSection={
|
leftSection={<div style={{ color: "var(--tools-text-and-icon-color)" }}>{tool.icon}</div>}
|
||||||
<div style={{ color: 'var(--tools-text-and-icon-color)' }}>
|
|
||||||
{tool.icon}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
fullWidth
|
fullWidth
|
||||||
justify="flex-start"
|
justify="flex-start"
|
||||||
style={{
|
style={{
|
||||||
borderRadius: '6px',
|
borderRadius: "6px",
|
||||||
color: 'var(--tools-text-and-icon-color)',
|
color: "var(--tools-text-and-icon-color)",
|
||||||
padding: '8px 12px'
|
padding: "8px 12px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ textAlign: 'left' }}>
|
<div style={{ textAlign: "left" }}>
|
||||||
<div style={{ fontWeight: 500 }}>{tool.name}</div>
|
<div style={{ fontWeight: 500 }}>{tool.name}</div>
|
||||||
<Text size="xs" c="dimmed" style={{ marginTop: '2px' }}>
|
<Text size="xs" c="dimmed" style={{ marginTop: "2px" }}>
|
||||||
{tool.description}
|
{tool.description}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user