options everywhere!

This commit is contained in:
Anthony Stirling
2025-10-06 12:34:09 +01:00
parent f791f90bba
commit 65dbe62419
6 changed files with 505 additions and 38 deletions

View File

@@ -1981,3 +1981,35 @@ toolPanel.legacy.favorites=Favourites
toolPanel.legacy.recent=Recently used
toolPanel.legacy.favorite=Add to favourites
toolPanel.legacy.unfavorite=Remove from favourites
toolPanel.legacy.settings.title=Customise appearance
toolPanel.legacy.settings.iconBackground.label=Tool icon background
toolPanel.legacy.settings.iconBackground.description=When to show coloured backgrounds behind tool icons
toolPanel.legacy.settings.iconBackground.none=None
toolPanel.legacy.settings.iconBackground.hover=On hover
toolPanel.legacy.settings.iconBackground.always=Always
toolPanel.legacy.settings.iconColor.label=Tool icon colour
toolPanel.legacy.settings.iconColor.description=Colour scheme for tool icons
toolPanel.legacy.settings.iconColor.colored=Coloured
toolPanel.legacy.settings.iconColor.vibrant=Vibrant
toolPanel.legacy.settings.iconColor.monochrome=Monochrome
toolPanel.legacy.settings.sectionTitle.label=Section titles
toolPanel.legacy.settings.sectionTitle.description=Colour for category section titles
toolPanel.legacy.settings.sectionTitle.colored=Coloured
toolPanel.legacy.settings.sectionTitle.neutral=Neutral
toolPanel.legacy.settings.headerIcon.label=Section header icons
toolPanel.legacy.settings.headerIcon.description=Colour for Favourites/Recent icons
toolPanel.legacy.settings.headerIcon.colored=Coloured
toolPanel.legacy.settings.headerIcon.monochrome=Monochrome
toolPanel.legacy.settings.headerBadge.label=Section header badges
toolPanel.legacy.settings.headerBadge.description=Colour for count badges in section headers
toolPanel.legacy.settings.headerBadge.colored=Coloured
toolPanel.legacy.settings.headerBadge.neutral=Neutral
toolPanel.legacy.settings.border.label=Tool item borders
toolPanel.legacy.settings.border.description=Show borders around tool items
toolPanel.legacy.settings.border.visible=Visible
toolPanel.legacy.settings.border.hidden=Hidden
toolPanel.legacy.settings.hover.label=Hover effect intensity
toolPanel.legacy.settings.hover.description=How prominent the hover effect should be
toolPanel.legacy.settings.hover.subtle=Subtle
toolPanel.legacy.settings.hover.moderate=Moderate
toolPanel.legacy.settings.hover.prominent=Prominent

View File

@@ -33,7 +33,7 @@ const LegacyToolList = ({
}: LegacyToolListProps) => {
const { t } = useTranslation();
const { hotkeys } = useHotkeys();
const { toolRegistry, recentTools, favoriteTools, toggleFavorite, isFavorite } = useToolWorkflow();
const { toolRegistry, recentTools, favoriteTools, toggleFavorite, isFavorite, legacyToolSettings } = useToolWorkflow();
const { sections, searchGroups } = useToolSections(filteredTools, searchQuery);
@@ -85,6 +85,38 @@ const LegacyToolList = ({
? 'tool-panel__legacy-groups tool-panel__legacy-groups--detailed'
: 'tool-panel__legacy-groups tool-panel__legacy-groups--compact';
const getItemClasses = (isDetailed: boolean) => {
const base = isDetailed ? 'tool-panel__legacy-item--detailed' : '';
const border = legacyToolSettings.toolItemBorder === 'hidden' ? 'tool-panel__legacy-item--no-border' : '';
const hover = `tool-panel__legacy-item--hover-${legacyToolSettings.hoverIntensity}`;
return [base, border, hover].filter(Boolean).join(' ');
};
const getIconBackground = (categoryColor: string, isDetailed: boolean) => {
if (legacyToolSettings.iconBackground === 'none' || legacyToolSettings.iconBackground === 'hover') {
return 'transparent';
}
const baseColor = isDetailed ? 'var(--legacy-bg-icon-detailed)' : 'var(--legacy-bg-icon-compact)';
const blend1 = isDetailed ? '18%' : '15%';
const blend2 = isDetailed ? '8%' : '6%';
return `linear-gradient(135deg,
color-mix(in srgb, ${categoryColor} ${blend1}, ${baseColor}),
color-mix(in srgb, ${categoryColor} ${blend2}, ${baseColor})
)`;
};
const getIconStyle = () => {
if (legacyToolSettings.iconColorScheme === 'monochrome') {
return { filter: 'grayscale(1) opacity(0.8)' };
}
if (legacyToolSettings.iconColorScheme === 'vibrant') {
return { filter: 'saturate(1.5) brightness(1.1)' };
}
return {};
};
// Helper function to render a tool item
const renderToolItem = (id: string, tool: ToolRegistryEntry) => {
const matchedText = matchedTextMap.get(id);
@@ -123,25 +155,37 @@ const LegacyToolList = ({
// Detailed view
if (showDescriptions) {
const iconBg = getIconBackground(categoryColor, true);
const iconClasses = legacyToolSettings.iconBackground === 'hover'
? 'tool-panel__legacy-icon tool-panel__legacy-icon--hover-bg'
: 'tool-panel__legacy-icon';
const hoverBgDetailed = legacyToolSettings.iconBackground === 'hover'
? `linear-gradient(135deg,
color-mix(in srgb, ${categoryColor} 18%, var(--legacy-bg-icon-detailed)),
color-mix(in srgb, ${categoryColor} 8%, var(--legacy-bg-icon-detailed))
)`
: undefined;
return (
<button
key={id}
type="button"
className={`tool-panel__legacy-item tool-panel__legacy-item--detailed ${isSelected ? 'tool-panel__legacy-item--selected' : ''} tool-panel__legacy-item--with-star`}
className={`tool-panel__legacy-item ${getItemClasses(true)} ${isSelected ? 'tool-panel__legacy-item--selected' : ''} tool-panel__legacy-item--with-star`}
onClick={handleClick}
aria-disabled={isDisabled}
disabled={isDisabled}
style={{
['--legacy-icon-hover-bg' as any]: hoverBgDetailed,
}}
>
{tool.icon ? (
<span
className="tool-panel__legacy-icon"
className={iconClasses}
aria-hidden
style={{
background: `linear-gradient(135deg,
color-mix(in srgb, ${categoryColor} 18%, var(--legacy-bg-icon-detailed)),
color-mix(in srgb, ${categoryColor} 8%, var(--legacy-bg-icon-detailed))
)`,
color: categoryColor
background: iconBg,
...getIconStyle(),
}}
>
{iconNode}
@@ -189,25 +233,37 @@ const LegacyToolList = ({
}
// Compact view
const iconBg = getIconBackground(categoryColor, false);
const iconClasses = legacyToolSettings.iconBackground === 'hover'
? 'tool-panel__legacy-list-icon tool-panel__legacy-list-icon--hover-bg'
: 'tool-panel__legacy-list-icon';
const hoverBgCompact = legacyToolSettings.iconBackground === 'hover'
? `linear-gradient(135deg,
color-mix(in srgb, ${categoryColor} 15%, var(--legacy-bg-icon-compact)),
color-mix(in srgb, ${categoryColor} 6%, var(--legacy-bg-icon-compact))
)`
: undefined;
const compactButton = (
<button
key={id}
type="button"
className={`tool-panel__legacy-list-item ${isSelected ? 'tool-panel__legacy-list-item--selected' : ''} ${!isDisabled ? 'tool-panel__legacy-list-item--with-star' : ''}`}
className={`tool-panel__legacy-list-item ${getItemClasses(false)} ${isSelected ? 'tool-panel__legacy-list-item--selected' : ''} ${!isDisabled ? 'tool-panel__legacy-list-item--with-star' : ''}`}
onClick={handleClick}
aria-disabled={isDisabled}
disabled={isDisabled}
style={{
['--legacy-icon-hover-bg' as any]: hoverBgCompact,
}}
>
{tool.icon ? (
<span
className="tool-panel__legacy-list-icon"
className={iconClasses}
aria-hidden
style={{
background: `linear-gradient(135deg,
color-mix(in srgb, ${categoryColor} 15%, var(--legacy-bg-icon-compact)),
color-mix(in srgb, ${categoryColor} 6%, var(--legacy-bg-icon-compact))
)`,
color: categoryColor
background: iconBg,
...getIconStyle(),
}}
>
{iconNode}
@@ -278,14 +334,25 @@ const LegacyToolList = ({
<section className="tool-panel__legacy-group tool-panel__legacy-group--special">
<header className="tool-panel__legacy-section-header">
<div className="tool-panel__legacy-section-title">
<span className="tool-panel__legacy-section-icon" style={{ color: '#FFC107' }} aria-hidden>
<span
className="tool-panel__legacy-section-icon"
style={{
color: legacyToolSettings.headerIconColor === 'colored' ? '#FFC107' : 'var(--mantine-color-dimmed)',
...getIconStyle(),
}}
aria-hidden
>
<StarRoundedIcon />
</span>
<Text size="sm" fw={600} tt="uppercase" lts={0.5} c="dimmed">
{t('toolPanel.legacy.favorites', 'Favourites')}
</Text>
</div>
<Badge size="sm" variant="light" color="yellow">
<Badge
size="sm"
variant="light"
color={legacyToolSettings.headerBadgeColor === 'colored' ? 'yellow' : 'gray'}
>
{favoriteToolItems.length}
</Badge>
</header>
@@ -305,14 +372,25 @@ const LegacyToolList = ({
<section className="tool-panel__legacy-group tool-panel__legacy-group--special">
<header className="tool-panel__legacy-section-header">
<div className="tool-panel__legacy-section-title">
<span className="tool-panel__legacy-section-icon" style={{ color: '#1BB1D4' }} aria-hidden>
<span
className="tool-panel__legacy-section-icon"
style={{
color: legacyToolSettings.headerIconColor === 'colored' ? '#1BB1D4' : 'var(--mantine-color-dimmed)',
...getIconStyle(),
}}
aria-hidden
>
<HistoryRoundedIcon />
</span>
<Text size="sm" fw={600} tt="uppercase" lts={0.5} c="dimmed">
{t('toolPanel.legacy.recent', 'Recently used')}
</Text>
</div>
<Badge size="sm" variant="light" color="cyan">
<Badge
size="sm"
variant="light"
color={legacyToolSettings.headerBadgeColor === 'colored' ? 'cyan' : 'gray'}
>
{recentToolItems.length}
</Badge>
</header>
@@ -345,20 +423,37 @@ const LegacyToolList = ({
<div className="tool-panel__legacy-section-title">
<span
className="tool-panel__legacy-section-icon"
style={{ color: categoryColor }}
style={{
color: legacyToolSettings.sectionTitleColor === 'colored' ? categoryColor : 'var(--mantine-color-dimmed)',
...getIconStyle(),
}}
aria-hidden
>
{getSubcategoryIcon(subcategoryId)}
</span>
<Text size="sm" fw={600} tt="uppercase" lts={0.5} style={{ color: categoryColor }}>
<Text
size="sm"
fw={600}
tt="uppercase"
lts={0.5}
style={{
color: legacyToolSettings.sectionTitleColor === 'colored' ? categoryColor : undefined,
}}
c={legacyToolSettings.sectionTitleColor === 'neutral' ? 'dimmed' : undefined}
>
{getSubcategoryLabel(t, subcategoryId)}
</Text>
</div>
<Badge size="sm" variant="light" style={{
backgroundColor: `color-mix(in srgb, ${categoryColor} 15%, transparent)`,
color: categoryColor,
borderColor: `color-mix(in srgb, ${categoryColor} 30%, transparent)`
}}>
<Badge
size="sm"
variant="light"
style={legacyToolSettings.sectionTitleColor === 'colored' ? {
backgroundColor: `color-mix(in srgb, ${categoryColor} 15%, transparent)`,
color: categoryColor,
borderColor: `color-mix(in srgb, ${categoryColor} 30%, transparent)`
} : undefined}
color={legacyToolSettings.sectionTitleColor === 'neutral' ? 'gray' : undefined}
>
{tools.length}
</Badge>
</header>

View File

@@ -0,0 +1,252 @@
import { ActionIcon, Drawer, Radio, SegmentedControl, Stack, Text } from '@mantine/core';
import { useTranslation } from 'react-i18next';
import TuneRoundedIcon from '@mui/icons-material/TuneRounded';
import { useState } from 'react';
export interface LegacyToolStyleSettings {
iconBackground: 'none' | 'hover' | 'always';
iconColorScheme: 'colored' | 'vibrant' | 'monochrome';
sectionTitleColor: 'colored' | 'neutral';
headerIconColor: 'colored' | 'monochrome';
headerBadgeColor: 'colored' | 'neutral';
toolItemBorder: 'visible' | 'hidden';
hoverIntensity: 'subtle' | 'moderate' | 'prominent';
}
export const defaultLegacyToolSettings: LegacyToolStyleSettings = {
iconBackground: 'always',
iconColorScheme: 'colored',
sectionTitleColor: 'colored',
headerIconColor: 'colored',
headerBadgeColor: 'colored',
toolItemBorder: 'visible',
hoverIntensity: 'moderate',
};
interface LegacyToolSettingsProps {
settings: LegacyToolStyleSettings;
onChange: (settings: LegacyToolStyleSettings) => void;
}
const LegacyToolSettings = ({ settings, onChange }: LegacyToolSettingsProps) => {
const { t } = useTranslation();
const [opened, setOpened] = useState(false);
const updateSetting = <K extends keyof LegacyToolStyleSettings>(
key: K,
value: LegacyToolStyleSettings[K]
) => {
onChange({ ...settings, [key]: value });
};
return (
<>
<ActionIcon
variant="subtle"
radius="xl"
size="md"
onClick={() => setOpened(true)}
aria-label={t('toolPanel.legacy.settings.title', 'Customize appearance')}
>
<TuneRoundedIcon fontSize="small" />
</ActionIcon>
<Drawer
opened={opened}
onClose={() => setOpened(false)}
title={t('toolPanel.legacy.settings.title', 'Customize appearance')}
position="right"
size="md"
styles={{
root: { zIndex: 1300 },
overlay: { zIndex: 1300 },
inner: { zIndex: 1300 },
}}
>
<Stack gap="xl">
<div>
<Text size="sm" fw={600} mb="xs">
{t('toolPanel.legacy.settings.iconBackground.label', 'Tool icon background')}
</Text>
<Text size="xs" c="dimmed" mb="sm">
{t('toolPanel.legacy.settings.iconBackground.description', 'When to show colored backgrounds behind tool icons')}
</Text>
<SegmentedControl
fullWidth
value={settings.iconBackground}
onChange={(value) => updateSetting('iconBackground', value as any)}
data={[
{
label: t('toolPanel.legacy.settings.iconBackground.none', 'None'),
value: 'none',
},
{
label: t('toolPanel.legacy.settings.iconBackground.hover', 'On hover'),
value: 'hover',
},
{
label: t('toolPanel.legacy.settings.iconBackground.always', 'Always'),
value: 'always',
},
]}
/>
</div>
<div>
<Text size="sm" fw={600} mb="xs">
{t('toolPanel.legacy.settings.iconColor.label', 'Tool icon color')}
</Text>
<Text size="xs" c="dimmed" mb="sm">
{t('toolPanel.legacy.settings.iconColor.description', 'Color scheme for tool icons')}
</Text>
<SegmentedControl
fullWidth
value={settings.iconColorScheme}
onChange={(value) => updateSetting('iconColorScheme', value as any)}
data={[
{
label: t('toolPanel.legacy.settings.iconColor.colored', 'Colored'),
value: 'colored',
},
{
label: t('toolPanel.legacy.settings.iconColor.vibrant', 'Vibrant'),
value: 'vibrant',
},
{
label: t('toolPanel.legacy.settings.iconColor.monochrome', 'Monochrome'),
value: 'monochrome',
},
]}
/>
</div>
<div>
<Text size="sm" fw={600} mb="xs">
{t('toolPanel.legacy.settings.sectionTitle.label', 'Section titles')}
</Text>
<Text size="xs" c="dimmed" mb="sm">
{t('toolPanel.legacy.settings.sectionTitle.description', 'Color for category section titles')}
</Text>
<SegmentedControl
fullWidth
value={settings.sectionTitleColor}
onChange={(value) => updateSetting('sectionTitleColor', value as any)}
data={[
{
label: t('toolPanel.legacy.settings.sectionTitle.colored', 'Colored'),
value: 'colored',
},
{
label: t('toolPanel.legacy.settings.sectionTitle.neutral', 'Neutral'),
value: 'neutral',
},
]}
/>
</div>
<div>
<Text size="sm" fw={600} mb="xs">
{t('toolPanel.legacy.settings.headerIcon.label', 'Section header icons')}
</Text>
<Text size="xs" c="dimmed" mb="sm">
{t('toolPanel.legacy.settings.headerIcon.description', 'Color for Favorites/Recent icons')}
</Text>
<SegmentedControl
fullWidth
value={settings.headerIconColor}
onChange={(value) => updateSetting('headerIconColor', value as any)}
data={[
{
label: t('toolPanel.legacy.settings.headerIcon.colored', 'Colored'),
value: 'colored',
},
{
label: t('toolPanel.legacy.settings.headerIcon.monochrome', 'Monochrome'),
value: 'monochrome',
},
]}
/>
</div>
<div>
<Text size="sm" fw={600} mb="xs">
{t('toolPanel.legacy.settings.headerBadge.label', 'Section header badges')}
</Text>
<Text size="xs" c="dimmed" mb="sm">
{t('toolPanel.legacy.settings.headerBadge.description', 'Color for count badges in section headers')}
</Text>
<SegmentedControl
fullWidth
value={settings.headerBadgeColor}
onChange={(value) => updateSetting('headerBadgeColor', value as any)}
data={[
{
label: t('toolPanel.legacy.settings.headerBadge.colored', 'Colored'),
value: 'colored',
},
{
label: t('toolPanel.legacy.settings.headerBadge.neutral', 'Neutral'),
value: 'neutral',
},
]}
/>
</div>
<div>
<Text size="sm" fw={600} mb="xs">
{t('toolPanel.legacy.settings.border.label', 'Tool item borders')}
</Text>
<Text size="xs" c="dimmed" mb="sm">
{t('toolPanel.legacy.settings.border.description', 'Show borders around tool items')}
</Text>
<SegmentedControl
fullWidth
value={settings.toolItemBorder}
onChange={(value) => updateSetting('toolItemBorder', value as any)}
data={[
{
label: t('toolPanel.legacy.settings.border.visible', 'Visible'),
value: 'visible',
},
{
label: t('toolPanel.legacy.settings.border.hidden', 'Hidden'),
value: 'hidden',
},
]}
/>
</div>
<div>
<Text size="sm" fw={600} mb="xs">
{t('toolPanel.legacy.settings.hover.label', 'Hover effect intensity')}
</Text>
<Text size="xs" c="dimmed" mb="sm">
{t('toolPanel.legacy.settings.hover.description', 'How prominent the hover effect should be')}
</Text>
<Radio.Group
value={settings.hoverIntensity}
onChange={(value) => updateSetting('hoverIntensity', value as any)}
>
<Stack gap="xs">
<Radio
value="subtle"
label={t('toolPanel.legacy.settings.hover.subtle', 'Subtle')}
/>
<Radio
value="moderate"
label={t('toolPanel.legacy.settings.hover.moderate', 'Moderate')}
/>
<Radio
value="prominent"
label={t('toolPanel.legacy.settings.hover.prominent', 'Prominent')}
/>
</Stack>
</Radio.Group>
</div>
</Stack>
</Drawer>
</>
);
};
export default LegacyToolSettings;

View File

@@ -4,9 +4,11 @@ import ViewSidebarRoundedIcon from '@mui/icons-material/ViewSidebarRounded';
import { useTranslation } from 'react-i18next';
import ToolSearch from './toolPicker/ToolSearch';
import LegacyToolList from './LegacyToolList';
import LegacyToolSettings from './LegacyToolSettings';
import { ToolRegistryEntry } from '../../data/toolsTaxonomy';
import { ToolId } from '../../types/toolId';
import { useFocusTrap } from '../../hooks/tools/useFocusTrap';
import { useToolWorkflow } from '../../contexts/ToolWorkflowContext';
import { BASE_PATH } from '../../constants/app';
import './ToolPanel.css';
@@ -46,6 +48,7 @@ const LegacyToolSurface = ({
}: LegacyToolSurfaceProps) => {
const { t } = useTranslation();
const { colorScheme } = useMantineColorScheme();
const { legacyToolSettings, setLegacyToolSettings } = useToolWorkflow();
const [isExiting, setIsExiting] = useState(false);
const surfaceRef = useRef<HTMLDivElement>(null);
@@ -110,17 +113,23 @@ const LegacyToolSurface = ({
<img src={brandIconSrc} alt="" className="tool-panel__legacy-brand-icon" />
<img src={brandTextSrc} alt={brandAltText} className="tool-panel__legacy-brand-text" />
</div>
<Tooltip label={toggleLabel} position="bottom" withArrow>
<ActionIcon
variant="subtle"
radius="xl"
size="md"
onClick={handleExit}
aria-label={toggleLabel}
>
<ViewSidebarRoundedIcon fontSize="small" />
</ActionIcon>
</Tooltip>
<div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center' }}>
<LegacyToolSettings
settings={legacyToolSettings}
onChange={setLegacyToolSettings}
/>
<Tooltip label={toggleLabel} position="bottom" withArrow>
<ActionIcon
variant="subtle"
radius="xl"
size="md"
onClick={handleExit}
aria-label={toggleLabel}
>
<ViewSidebarRoundedIcon fontSize="small" />
</ActionIcon>
</Tooltip>
</div>
</header>
<div className="tool-panel__legacy-controls">

View File

@@ -530,3 +530,42 @@
column-width: 14rem;
}
}
/* Dynamic settings support */
/* No border variant */
.tool-panel__legacy-item--no-border,
.tool-panel__legacy-list-item--no-border {
border: none !important;
}
/* Hover intensity variants */
.tool-panel__legacy-item--hover-subtle:hover,
.tool-panel__legacy-list-item--hover-subtle:hover {
background: var(--legacy-hover-subtle);
transform: none;
}
.tool-panel__legacy-item--hover-moderate:hover,
.tool-panel__legacy-list-item--hover-moderate:hover {
background: var(--legacy-hover);
transform: translateY(-2px);
}
.tool-panel__legacy-item--hover-prominent:hover,
.tool-panel__legacy-list-item--hover-prominent:hover {
background: var(--legacy-hover-prominent);
transform: translateY(-3px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* Hover-only icon background */
.tool-panel__legacy-icon--hover-bg,
.tool-panel__legacy-list-icon--hover-bg {
transition: background 0.2s ease;
}
.tool-panel__legacy-item:hover .tool-panel__legacy-icon--hover-bg,
.tool-panel__legacy-list-item:hover .tool-panel__legacy-list-icon--hover-bg {
background: var(--legacy-icon-hover-bg) !important;
}

View File

@@ -13,6 +13,7 @@ import { useNavigationUrlSync } from '../hooks/useUrlSync';
import { getDefaultWorkbench } from '../types/workbench';
import { filterToolRegistryByQuery } from '../utils/toolSearch';
import { useToolHistory } from '../hooks/tools/useToolHistory';
import { LegacyToolStyleSettings, defaultLegacyToolSettings } from '../components/tools/LegacyToolSettings';
// State interface
type ToolPanelMode = 'sidebar' | 'legacy';
@@ -23,6 +24,7 @@ interface ToolWorkflowState {
leftPanelView: 'toolPicker' | 'toolContent' | 'hidden';
readerMode: boolean;
toolPanelMode: ToolPanelMode;
legacyToolSettings: LegacyToolStyleSettings;
// File/Preview State
previewFile: File | null;
@@ -38,6 +40,7 @@ type ToolWorkflowAction =
| { type: 'SET_LEFT_PANEL_VIEW'; payload: 'toolPicker' | 'toolContent' | 'hidden' }
| { type: 'SET_READER_MODE'; payload: boolean }
| { type: 'SET_TOOL_PANEL_MODE'; payload: ToolPanelMode }
| { type: 'SET_LEGACY_TOOL_SETTINGS'; payload: LegacyToolStyleSettings }
| { type: 'SET_PREVIEW_FILE'; payload: File | null }
| { type: 'SET_PAGE_EDITOR_FUNCTIONS'; payload: PageEditorFunctions | null }
| { type: 'SET_SEARCH_QUERY'; payload: string }
@@ -45,6 +48,7 @@ type ToolWorkflowAction =
// Initial state
export const TOOL_PANEL_MODE_STORAGE_KEY = 'toolPanelModePreference';
export const LEGACY_TOOL_SETTINGS_STORAGE_KEY = 'legacyToolStyleSettings';
const getStoredToolPanelMode = (): ToolPanelMode => {
if (typeof window === 'undefined') {
@@ -59,7 +63,24 @@ const getStoredToolPanelMode = (): ToolPanelMode => {
return 'sidebar';
};
const baseState: Omit<ToolWorkflowState, 'toolPanelMode'> = {
const getStoredLegacyToolSettings = (): LegacyToolStyleSettings => {
if (typeof window === 'undefined') {
return defaultLegacyToolSettings;
}
try {
const stored = window.localStorage.getItem(LEGACY_TOOL_SETTINGS_STORAGE_KEY);
if (stored) {
return { ...defaultLegacyToolSettings, ...JSON.parse(stored) };
}
} catch (e) {
console.error('Failed to parse legacy tool settings:', e);
}
return defaultLegacyToolSettings;
};
const baseState: Omit<ToolWorkflowState, 'toolPanelMode' | 'legacyToolSettings'> = {
sidebarsVisible: true,
leftPanelView: 'toolPicker',
readerMode: false,
@@ -71,6 +92,7 @@ const baseState: Omit<ToolWorkflowState, 'toolPanelMode'> = {
const createInitialState = (): ToolWorkflowState => ({
...baseState,
toolPanelMode: getStoredToolPanelMode(),
legacyToolSettings: getStoredLegacyToolSettings(),
});
// Reducer
@@ -84,6 +106,8 @@ function toolWorkflowReducer(state: ToolWorkflowState, action: ToolWorkflowActio
return { ...state, readerMode: action.payload };
case 'SET_TOOL_PANEL_MODE':
return { ...state, toolPanelMode: action.payload };
case 'SET_LEGACY_TOOL_SETTINGS':
return { ...state, legacyToolSettings: action.payload };
case 'SET_PREVIEW_FILE':
return { ...state, previewFile: action.payload };
case 'SET_PAGE_EDITOR_FUNCTIONS':
@@ -94,6 +118,7 @@ function toolWorkflowReducer(state: ToolWorkflowState, action: ToolWorkflowActio
return {
...baseState,
toolPanelMode: state.toolPanelMode,
legacyToolSettings: state.legacyToolSettings,
searchQuery: state.searchQuery,
};
default:
@@ -114,6 +139,7 @@ interface ToolWorkflowContextValue extends ToolWorkflowState {
setLeftPanelView: (view: 'toolPicker' | 'toolContent' | 'hidden') => void;
setReaderMode: (mode: boolean) => void;
setToolPanelMode: (mode: ToolPanelMode) => void;
setLegacyToolSettings: (settings: LegacyToolStyleSettings) => void;
setPreviewFile: (file: File | null) => void;
setPageEditorFunctions: (functions: PageEditorFunctions | null) => void;
setSearchQuery: (query: string) => void;
@@ -200,6 +226,10 @@ export function ToolWorkflowProvider({ children }: ToolWorkflowProviderProps) {
dispatch({ type: 'SET_TOOL_PANEL_MODE', payload: mode });
}, []);
const setLegacyToolSettings = useCallback((settings: LegacyToolStyleSettings) => {
dispatch({ type: 'SET_LEGACY_TOOL_SETTINGS', payload: settings });
}, []);
const setPreviewFile = useCallback((file: File | null) => {
dispatch({ type: 'SET_PREVIEW_FILE', payload: file });
if (file) {
@@ -223,6 +253,14 @@ export function ToolWorkflowProvider({ children }: ToolWorkflowProviderProps) {
window.localStorage.setItem(TOOL_PANEL_MODE_STORAGE_KEY, state.toolPanelMode);
}, [state.toolPanelMode]);
React.useEffect(() => {
if (typeof window === 'undefined') {
return;
}
window.localStorage.setItem(LEGACY_TOOL_SETTINGS_STORAGE_KEY, JSON.stringify(state.legacyToolSettings));
}, [state.legacyToolSettings]);
// Tool reset methods
const registerToolReset = useCallback((toolId: string, resetFunction: () => void) => {
setToolResetFunctions(prev => ({ ...prev, [toolId]: resetFunction }));
@@ -327,6 +365,7 @@ export function ToolWorkflowProvider({ children }: ToolWorkflowProviderProps) {
setLeftPanelView,
setReaderMode,
setToolPanelMode,
setLegacyToolSettings,
setPreviewFile,
setPageEditorFunctions,
setSearchQuery,
@@ -363,6 +402,7 @@ export function ToolWorkflowProvider({ children }: ToolWorkflowProviderProps) {
setLeftPanelView,
setReaderMode,
setToolPanelMode,
setLegacyToolSettings,
setPreviewFile,
setPageEditorFunctions,
setSearchQuery,