mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 05:10:16 +03:00
Merge branch 'main' into feature/failure-notifications
This commit is contained in:
+11
-4
@@ -25,6 +25,13 @@ export default function WorkbenchBarMobileActions({
|
||||
}: WorkbenchBarActionsProps) {
|
||||
const { t } = useTranslation();
|
||||
const exportDisabled = actionsDisabled || policyEnforcing;
|
||||
const showPrint = currentView === "viewer";
|
||||
const showFileActions = !isCustomView;
|
||||
|
||||
// Custom workbench views own their content, so none of these apply. The
|
||||
// desktop cluster renders nothing at all in that case; without this the
|
||||
// trigger would still be there, opening an empty dropdown.
|
||||
if (!showPrint && !showFileActions) return null;
|
||||
|
||||
return (
|
||||
<Menu shadow="md" width={230} position="bottom-end">
|
||||
@@ -39,7 +46,7 @@ export default function WorkbenchBarMobileActions({
|
||||
</ActionIcon>
|
||||
</Menu.Target>
|
||||
<Menu.Dropdown>
|
||||
{currentView === "viewer" && (
|
||||
{showPrint && (
|
||||
<Menu.Item
|
||||
leftSection={<PrintIcon sx={{ fontSize: "1.1rem" }} />}
|
||||
disabled={exportDisabled}
|
||||
@@ -48,7 +55,7 @@ export default function WorkbenchBarMobileActions({
|
||||
{t("workbenchBar.print", "Print PDF")}
|
||||
</Menu.Item>
|
||||
)}
|
||||
{!isCustomView && (
|
||||
{showFileActions && (
|
||||
<Menu.Item
|
||||
leftSection={
|
||||
<LocalIcon
|
||||
@@ -63,7 +70,7 @@ export default function WorkbenchBarMobileActions({
|
||||
{downloadLabel}
|
||||
</Menu.Item>
|
||||
)}
|
||||
{!isCustomView && saveAsIconName && (
|
||||
{showFileActions && saveAsIconName && (
|
||||
<Menu.Item
|
||||
leftSection={
|
||||
<LocalIcon icon={saveAsIconName} width="1.1rem" height="1.1rem" />
|
||||
@@ -74,7 +81,7 @@ export default function WorkbenchBarMobileActions({
|
||||
{t("workbenchBar.saveAs", "Save As")}
|
||||
</Menu.Item>
|
||||
)}
|
||||
{!isCustomView && (
|
||||
{showFileActions && (
|
||||
<>
|
||||
<Menu.Divider />
|
||||
<Menu.Item
|
||||
|
||||
@@ -282,6 +282,9 @@ export default function RightSidebar() {
|
||||
onShowAllTools={handleShowAllTools}
|
||||
onToolSelect={handleToolSelectWithTransition}
|
||||
compact={false}
|
||||
/* Mobile keeps the workbench bar - and with it the super search -
|
||||
on the other slide, so the list needs its own filter. */
|
||||
showSearch={isMobile}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
|
||||
@@ -183,6 +183,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* In-panel tool filter. Aligned with .tool-picker__compact's inline padding so
|
||||
the field lines up with the tool rows underneath it. */
|
||||
.tool-panel__search {
|
||||
flex-shrink: 0;
|
||||
padding: 0.5rem var(--mantine-spacing-sm) 0;
|
||||
}
|
||||
|
||||
.tool-panel__search .search-input-container {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tool-panel__compact-header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useToolWorkflow } from "@app/contexts/ToolWorkflowContext";
|
||||
import ToolPicker from "@app/components/tools/ToolPicker";
|
||||
import SearchResults from "@app/components/tools/SearchResults";
|
||||
import ToolRenderer from "@app/components/tools/ToolRenderer";
|
||||
import ToolSearch from "@app/components/tools/toolPicker/ToolSearch";
|
||||
import { ToolPanelViewerBar } from "@app/components/tools/ToolPanelViewerBar";
|
||||
import { ToolId } from "@app/types/toolId";
|
||||
|
||||
@@ -20,6 +21,11 @@ interface ToolPanelProps {
|
||||
onToolSelect?: (id: ToolId) => void;
|
||||
/** Whether to render the compact (favourites + recommended only) view. */
|
||||
compact?: boolean;
|
||||
/**
|
||||
* Render a tool filter at the head of the panel. Set where the workbench
|
||||
* bar's super search is out of reach, so the list stays searchable in place.
|
||||
*/
|
||||
showSearch?: boolean;
|
||||
}
|
||||
|
||||
/** Tool list and renderer for the right rail; rail chrome lives in RightSidebar. */
|
||||
@@ -28,24 +34,44 @@ export default function ToolPanel({
|
||||
onShowAllTools,
|
||||
onToolSelect,
|
||||
compact: compactProp,
|
||||
showSearch = false,
|
||||
}: ToolPanelProps) {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
leftPanelView,
|
||||
searchQuery,
|
||||
setSearchQuery,
|
||||
filteredTools,
|
||||
toolRegistry,
|
||||
selectedToolKey,
|
||||
handleToolSelect,
|
||||
setPreviewFile,
|
||||
} = useToolWorkflow();
|
||||
const selectTool = onToolSelect ?? handleToolSelect;
|
||||
|
||||
// Only offer the filter over the list itself; once a tool is open the panel
|
||||
// belongs to that tool. Deriving the results branch from the same flag keeps
|
||||
// the input and what it filters from drifting apart.
|
||||
const panelSearch = showSearch && leftPanelView === "toolPicker";
|
||||
const searching = searchQuery.trim().length > 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Viewer mode tools — annotate, redact, form fill */}
|
||||
<ToolPanelViewerBar />
|
||||
|
||||
{allToolsView && searchQuery.trim().length > 0 ? (
|
||||
{panelSearch && (
|
||||
<div className="tool-panel__search">
|
||||
<ToolSearch
|
||||
value={searchQuery}
|
||||
onChange={setSearchQuery}
|
||||
toolRegistry={toolRegistry}
|
||||
mode="filter"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{searching && (allToolsView || panelSearch) ? (
|
||||
<div className="flex-1 flex flex-col overflow-y-auto">
|
||||
<SearchResults
|
||||
filteredTools={filteredTools}
|
||||
@@ -59,7 +85,7 @@ export default function ToolPanel({
|
||||
selectedToolKey={selectedToolKey}
|
||||
onSelect={(id) => selectTool(id as ToolId)}
|
||||
filteredTools={filteredTools}
|
||||
isSearching={Boolean(searchQuery && searchQuery.trim().length > 0)}
|
||||
isSearching={searching}
|
||||
compact={compactProp ?? !allToolsView}
|
||||
onShowAllTools={onShowAllTools}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user