- Links in developer tools section should be links, not buttons

- Text seems to be slightly clipped at various zoom levels in the all tools sidebar. 
- Investigate colors on the light mode search section 
This commit is contained in:
EthanHealy01 2025-08-14 15:40:02 +01:00
parent 568daeff02
commit b2bea0ede6
7 changed files with 99 additions and 46 deletions

View File

@ -53,7 +53,7 @@ const FitText: React.FC<FitTextProps> = ({
const clampStyles: CSSProperties = { const clampStyles: CSSProperties = {
// Multi-line clamp with ellipsis fallback // Multi-line clamp with ellipsis fallback
whiteSpace: lines === 1 ? 'nowrap' : 'normal', whiteSpace: lines === 1 ? 'nowrap' : 'normal',
overflow: 'hidden', overflow: 'visible',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
display: lines > 1 ? ('-webkit-box' as any) : undefined, display: lines > 1 ? ('-webkit-box' as any) : undefined,
WebkitBoxOrient: lines > 1 ? ('vertical' as any) : undefined, WebkitBoxOrient: lines > 1 ? ('vertical' as any) : undefined,

View File

@ -1,11 +1,12 @@
import React from 'react'; import React from 'react';
import { TextInput, useMantineColorScheme } from '@mantine/core'; import { useMantineColorScheme } from '@mantine/core';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useRainbowThemeContext } from '../shared/RainbowThemeProvider'; import { useRainbowThemeContext } from '../shared/RainbowThemeProvider';
import { useToolPanelState, useToolSelection, useWorkbenchState } from '../../contexts/ToolWorkflowContext'; import { useToolPanelState, useToolSelection, useWorkbenchState } from '../../contexts/ToolWorkflowContext';
import ToolPicker from './ToolPicker'; import ToolPicker from './ToolPicker';
import SearchResults from './SearchResults'; import SearchResults from './SearchResults';
import ToolRenderer from './ToolRenderer'; import ToolRenderer from './ToolRenderer';
import ToolSearch from './toolPicker/ToolSearch';
import { useSidebarContext } from "../../contexts/SidebarContext"; import { useSidebarContext } from "../../contexts/SidebarContext";
import rainbowStyles from '../../styles/rainbow.module.css'; import rainbowStyles from '../../styles/rainbow.module.css';
@ -25,6 +26,7 @@ export default function ToolPanel() {
isPanelVisible, isPanelVisible,
searchQuery, searchQuery,
filteredTools, filteredTools,
toolRegistry,
setSearchQuery, setSearchQuery,
handleBackToTools handleBackToTools
} = useToolPanelState(); } = useToolPanelState();
@ -58,29 +60,11 @@ export default function ToolPanel() {
marginBottom: (leftPanelView === 'toolContent') ? '1rem' : 0, marginBottom: (leftPanelView === 'toolContent') ? '1rem' : 0,
}} }}
> >
<TextInput <ToolSearch
placeholder={t("toolPicker.searchPlaceholder", "Search tools...")}
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.currentTarget.value)} onChange={setSearchQuery}
autoComplete="off" toolRegistry={toolRegistry}
size="sm" mode="filter"
styles={{
root: {
marginTop: '0.5rem',
marginBottom: '0.5rem',
},
input: {
backgroundColor: colorScheme === 'dark' ? '#4B525A' : '#FFFFFF',
color: colorScheme === 'dark' ? '#FFFFFF' : '#6B7382',
border: 'none',
boxShadow: 'none',
borderBottom: leftPanelView === 'toolContent' ? `1px solid ${colorScheme === 'dark' ? '#3A4047' : '#E0E0E0'}` : 'none',
},
section: {
color: colorScheme === 'dark' ? '#FFFFFF' : '#6B7382',
}
}}
leftSection={<span className="material-symbols-rounded" style={{ fontSize: 16, color: colorScheme === 'dark' ? '#FFFFFF' : '#6B7382' }}>search</span>}
/> />
</div> </div>

View File

@ -12,11 +12,21 @@ interface ToolButtonProps {
} }
const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect }) => { const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect }) => {
const handleClick = (id: string) => {
if (tool.link) {
// Open external link in new tab
window.open(tool.link, '_blank', 'noopener,noreferrer');
return;
}
// Normal tool selection
onSelect(id);
};
return ( return (
<Tooltip content={tool.description} position="right" arrow={true} delay={500}> <Tooltip content={tool.description} position="right" arrow={true} delay={500}>
<Button <Button
variant={isSelected ? "filled" : "subtle"} variant={isSelected ? "filled" : "subtle"}
onClick={() => onSelect(id)} onClick={()=> handleClick(id)}
size="md" size="md"
radius="md" radius="md"
leftSection={<div className="tool-button-icon" style={{ color: "var(--tools-text-and-icon-color)" }}>{tool.icon}</div>} leftSection={<div className="tool-button-icon" style={{ color: "var(--tools-text-and-icon-color)" }}>{tool.icon}</div>}
@ -28,7 +38,7 @@ const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect
<FitText <FitText
text={tool.name} text={tool.name}
lines={1} lines={1}
minimumFontScale={0.6} minimumFontScale={0.8}
as="span" as="span"
style={{ display: 'inline-block', maxWidth: '100%' }} style={{ display: 'inline-block', maxWidth: '100%' }}
/> />

View File

@ -70,4 +70,40 @@
.tool-button-icon { .tool-button-icon {
font-size: 1rem; font-size: 1rem;
line-height: 1; line-height: 1;
}
.search-input-container {
position: relative;
margin-top: 0.5rem;
margin-bottom: 0.5rem;
display: flex;
align-items: center;
}
.search-icon {
position: absolute;
left: 12px;
z-index: 1;
font-size: 16px;
pointer-events: none;
}
.search-input-field {
width: 100%;
padding: 8px 12px 8px 40px;
border: none;
border-radius: 6px;
font-size: 14px;
outline: none;
box-shadow: none;
}
.search-input-field::placeholder {
color: var(--search-text-and-icon-color);
opacity: 1;
}
.search-input-field:focus {
outline: none;
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
} }

View File

@ -1,8 +1,8 @@
import React, { useState, useRef, useEffect, useMemo } from "react"; import React, { useState, useRef, useEffect, useMemo } from "react";
import { TextInput, Stack, Button, Text } from "@mantine/core"; import { TextInput, Stack, Button, Text, useMantineColorScheme } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import SearchIcon from "@mui/icons-material/Search";
import { type ToolRegistryEntry } from "../../../data/toolRegistry"; import { type ToolRegistryEntry } from "../../../data/toolRegistry";
import './ToolPicker.css';
interface ToolSearchProps { interface ToolSearchProps {
value: string; value: string;
@ -22,6 +22,7 @@ const ToolSearch = ({
selectedToolKey selectedToolKey
}: ToolSearchProps) => { }: ToolSearchProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { colorScheme } = useMantineColorScheme();
const [dropdownOpen, setDropdownOpen] = useState(false); const [dropdownOpen, setDropdownOpen] = useState(false);
const searchRef = useRef<HTMLInputElement>(null); const searchRef = useRef<HTMLInputElement>(null);
@ -55,16 +56,24 @@ const ToolSearch = ({
}, []); }, []);
const searchInput = ( const searchInput = (
<TextInput <div className="search-input-container">
ref={searchRef} <span className="material-symbols-rounded search-icon" style={{ color: colorScheme === 'dark' ? '#FFFFFF' : '#6B7382' }}>
placeholder={t("toolPicker.searchPlaceholder", "Search tools...")} search
value={value} </span>
radius="md" <input
onChange={(e) => handleSearchChange(e.currentTarget.value)} ref={searchRef}
autoComplete="off" type="text"
className="search-input rounded-lg" placeholder={t("toolPicker.searchPlaceholder", "Search tools...")}
leftSection={<SearchIcon sx={{ fontSize: 16, color: 'var(--tools-text-and-icon-color)' }} />} value={value}
/> onChange={(e) => handleSearchChange(e.currentTarget.value)}
autoComplete="off"
className="search-input-field"
style={{
backgroundColor: colorScheme === 'dark' ? '#4B525A' : '#FFFFFF',
color: colorScheme === 'dark' ? '#FFFFFF' : '#6B7382',
}}
/>
</div>
); );
if (mode === 'filter') { if (mode === 'filter') {

View File

@ -17,6 +17,10 @@ export type ToolRegistryEntry = {
maxFiles?: number; maxFiles?: number;
supportedFormats?: string[]; supportedFormats?: string[];
endpoints?: string[]; endpoints?: string[];
// Optional key to distinguish between regular tools and links
link?: string;
type?: string;
}; };
export type ToolRegistry = { export type ToolRegistry = {
@ -554,36 +558,40 @@ export const flatToolRegistryMap: ToolRegistry = {
name: "API", name: "API",
component: null, component: null,
view: "external", view: "external",
description: "https://stirlingpdf.io/swagger-ui/5.21.0/index.html", description: "Link to API documentation",
category: "Advanced Tools", category: "Advanced Tools",
subcategory: "Developer Tools" subcategory: "Developer Tools",
link: "https://stirlingpdf.io/swagger-ui/5.21.0/index.html"
}, },
"dev-folder-scanning": { "dev-folder-scanning": {
icon: <span className="material-symbols-rounded" style={{ color: '#2F7BF6' }}>open_in_new</span>, icon: <span className="material-symbols-rounded" style={{ color: '#2F7BF6' }}>open_in_new</span>,
name: "Automated Folder Scanning", name: "Automated Folder Scanning",
component: null, component: null,
view: "external", view: "external",
description: "https://docs.stirlingpdf.com/Advanced%20Configuration/Folder%20Scanning/", description: "Link to automated folder scanning guide",
category: "Advanced Tools", category: "Advanced Tools",
subcategory: "Developer Tools" subcategory: "Developer Tools",
link: "https://docs.stirlingpdf.com/Advanced%20Configuration/Folder%20Scanning/"
}, },
"dev-sso-guide": { "dev-sso-guide": {
icon: <span className="material-symbols-rounded" style={{ color: '#2F7BF6' }}>open_in_new</span>, icon: <span className="material-symbols-rounded" style={{ color: '#2F7BF6' }}>open_in_new</span>,
name: "SSO Guide", name: "SSO Guide",
component: null, component: null,
view: "external", view: "external",
description: "https://docs.stirlingpdf.com/Advanced%20Configuration/Single%20Sign-On%20Configuration", description: "Link to SSO guide",
category: "Advanced Tools", category: "Advanced Tools",
subcategory: "Developer Tools" subcategory: "Developer Tools",
link: "https://docs.stirlingpdf.com/Advanced%20Configuration/Single%20Sign-On%20Configuration",
}, },
"dev-airgapped": { "dev-airgapped": {
icon: <span className="material-symbols-rounded" style={{ color: '#2F7BF6' }}>open_in_new</span>, icon: <span className="material-symbols-rounded" style={{ color: '#2F7BF6' }}>open_in_new</span>,
name: "Air-gapped Setup", name: "Air-gapped Setup",
component: null, component: null,
view: "external", view: "external",
description: "https://docs.stirlingpdf.com/Pro/#activation", description: "Link to air-gapped setup guide",
category: "Advanced Tools", category: "Advanced Tools",
subcategory: "Developer Tools" subcategory: "Developer Tools",
link: "https://docs.stirlingpdf.com/Pro/#activation"
}, },

View File

@ -135,6 +135,9 @@
--text-brand: var(--color-gray-700); --text-brand: var(--color-gray-700);
--text-brand-accent: #DC2626; --text-brand-accent: #DC2626;
/* Placeholder text colors */
--search-text-and-icon-color: #6B7382;
/* container */ /* container */
--landing-paper-bg: var(--bg-surface); --landing-paper-bg: var(--bg-surface);
--landing-inner-paper-bg: #EEF8FF; --landing-inner-paper-bg: #EEF8FF;
@ -277,6 +280,9 @@
/* Subcategory title styling (dark mode) */ /* Subcategory title styling (dark mode) */
--tool-subcategory-text-color: #9CA3AF; /* lighter text in dark mode as well */ --tool-subcategory-text-color: #9CA3AF; /* lighter text in dark mode as well */
--tool-subcategory-rule-color: #3A4047; /* doubly lighter (relative) line in dark */ --tool-subcategory-rule-color: #3A4047; /* doubly lighter (relative) line in dark */
/* Placeholder text colors (dark mode) */
--search-text-and-icon-color: #FFFFFF !important;
} }
/* Dropzone drop state styling */ /* Dropzone drop state styling */