Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# Logs
logs
*.log
npm-debug.log*
Expand Down Expand Up @@ -33,3 +32,5 @@ playwright-report/
test-results/
e2e/screenshots/
*.png
.cursor/
# Logs
145 changes: 145 additions & 0 deletions docs/features/toolbar-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Toolbar Configuration

## Overview

This feature allows users to hide the toolbar and default to a specific shape tool or the function tool. Configuration is accessible via the global configuration panel.

## User Stories

1. As a user, I want to be able to hide the toolbar to maximize the canvas space for drawing.
2. As a user, I want to configure a default tool (shape or function) to be selected when the application loads.
3. As a user, I want these preferences to be persisted across sessions.
4. [x] As a user, I want to be able to share a URL with a pre-selected tool.

## Implementation Checklist

<details>
<summary>[x] Configuration Context Updates</summary>

- [x] Add `isToolbarVisible` boolean setting (default: true)
- [x] Add `defaultTool` string setting for tool selection
- [x] Add setter functions for both settings
- [x] Implement localStorage persistence
- [x] Update type definitions
</details>

<details>
<summary>[x] ConfigModal UI Updates</summary>

- [x] Add "Display" tab to configuration modal
- [x] Add toolbar visibility toggle switch
- [x] Add default tool dropdown selection in "Sharing" tab
- [x] Create appropriate labeling and help text
- [x] Add share URL button that copies a URL with the selected default tool
</details>

<details>
<summary>[-] Index Component Integration</summary>

- [x] Conditionally render toolbar based on visibility setting
- [-] ~~Add toolbar toggle button when toolbar is hidden~~ (UI requires settings panel)
- [x] Initialize with default tool on application load
- [x] Support function tool default with auto-opening formula editor
- [ ] Add keyboard shortcut for toggling toolbar (optional)
</details>

<details>
<summary>[x] URL Integration</summary>

- [x] Add tool selection parameter to URL encoding functions
- [x] Parse tool parameter from URL on application load
- [x] Apply tool selection from URL or fall back to user preference
- [x] Update URL when tool selection changes
- [x] Add UI for generating share URLs with specific tool parameter
- [x] Implement clipboard copy functionality for sharing URLs
</details>

<details>
<summary>[x] Translations</summary>

- [x] Add translation keys for new UI elements
- [x] Update all supported language files
</details>

<details>
<summary>[-] Testing</summary>

- [x] Unit tests for context functionality (Partially done)
- [x] Component tests for ConfigModal UI
- [x] Integration tests for toolbar visibility (Partially done)
- [x] Test default tool selection behavior (Partially done)
- [x] Test URL tool parameter functionality
- [ ] E2E tests for hidden toolbar workflow
</details>

## Technical Details

### Configuration Context

```typescript
// New settings for the GlobalConfigContextType
isToolbarVisible: boolean;
setToolbarVisible: (visible: boolean) => void;
defaultTool: string; // 'select', 'rectangle', 'circle', 'triangle', 'line', 'function'
setDefaultTool: (tool: string) => void;
```

### Display Tab UI Structure

```
Display Tab
├── Toolbar Section
│ ├── "Show Toolbar" toggle switch
│ └── Help text explaining the feature
└── Default Tool Section
├── "Default Tool" dropdown
│ ├── Select Tool
│ ├── Rectangle
│ ├── Circle
│ ├── Triangle
│ ├── Line
│ └── Function Plot
└── Help text explaining the feature
```

### URL Parameter

```
https://example.com/?shapes=...&formulas=...&grid=...&tool=rectangle
```

The `tool` parameter can have the following values:
- `select`
- `rectangle`
- `circle`
- `triangle`
- `line`
- `function`

Special handling notes:
- The `select` tool value sets the application to selection mode
- The `function` tool value opens the formula editor automatically
- All shape tools (`rectangle`, `circle`, etc.) set the drawing mode with that shape type

### Key UX Considerations

When the toolbar is hidden:
1. Maintain access to tools via the settings panel only
2. Move the application header into the freed toolbar space
3. Ensure the canvas still displays the current tool cursor
4. The configuration menu will still be accessible from the global controls

## Dependencies

- ConfigContext for settings management
- Toolbar component for visibility toggle
- FormulaEditor for default function tool support
- URL encoding utilities for tool parameter handling

## Implementation Examples

Additional implementation examples are available in:
- `docs/implementation-example-ConfigContext.md`
- `docs/implementation-example-ConfigModal.md`
- `docs/implementation-example-Index.md`
- `docs/implementation-example-URLEncoding.md`
130 changes: 130 additions & 0 deletions docs/features/toolbar-config/implementation-example-ConfigContext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Implementation Example: ConfigContext Updates

This document shows the implementation example for updating the `ConfigContext.tsx` file to support the new toolbar visibility and default tool selection features.

## Changes to GlobalConfigContextType

```typescript
// src/context/ConfigContext.tsx

// Updated GlobalConfigContextType
type GlobalConfigContextType = {
// Existing settings
language: string;
setLanguage: (language: string) => void;

openaiApiKey: string | null;
setOpenaiApiKey: (key: string | null) => Promise<void>;

loggingEnabled: boolean;
setLoggingEnabled: (enabled: boolean) => void;

isGlobalConfigModalOpen: boolean;
setGlobalConfigModalOpen: (isOpen: boolean) => void;

// New settings for toolbar
isToolbarVisible: boolean;
setToolbarVisible: (visible: boolean) => void;

defaultTool: string; // 'select', 'rectangle', 'circle', 'triangle', 'line', 'function'
setDefaultTool: (tool: string) => void;
};
```

## Update to STORAGE_KEYS

```typescript
// Constants for localStorage keys
const STORAGE_KEYS = {
// Existing keys
LANGUAGE: 'lang',
OPENAI_API_KEY: '_gp_oai_k',
MEASUREMENT_UNIT: 'mu',
LOGGING_ENABLED: LOGGER_STORAGE_KEY,

// New keys
TOOLBAR_VISIBLE: 'tb_vis',
DEFAULT_TOOL: 'def_tool',
};
```

## Update ConfigProvider Component

```typescript
const ConfigProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
// Existing state variables
const [language, setLanguage] = useState<string>(() => {
const storedLanguage = localStorage.getItem(STORAGE_KEYS.LANGUAGE);
return storedLanguage || navigator.language.split('-')[0] || 'en';
});

const [openaiApiKey, setOpenaiApiKeyState] = useState<string | null>(null);
const [isGlobalConfigModalOpen, setGlobalConfigModalOpen] = useState<boolean>(false);
const [loggingEnabled, setLoggingEnabledState] = useState<boolean>(isLoggingEnabled);

// Component-specific settings
const [pixelsPerUnit, setPixelsPerUnit] = useState<number>(60);
const [measurementUnit, setMeasurementUnit] = useState<MeasurementUnit>(() => {
const storedUnit = localStorage.getItem(STORAGE_KEYS.MEASUREMENT_UNIT);
return (storedUnit as MeasurementUnit) || 'cm';
});

const [isComponentConfigModalOpen, setComponentConfigModalOpen] = useState<boolean>(false);

// New state variables for toolbar configuration
const [isToolbarVisible, setToolbarVisibleState] = useState<boolean>(() => {
const storedValue = localStorage.getItem(STORAGE_KEYS.TOOLBAR_VISIBLE);
return storedValue === null ? true : storedValue === 'true';
});

const [defaultTool, setDefaultToolState] = useState<string>(() => {
const storedValue = localStorage.getItem(STORAGE_KEYS.DEFAULT_TOOL);
return storedValue || 'select';
});

// ... existing useEffects and functions ...

// Function to update toolbar visibility
const setToolbarVisible = useCallback((visible: boolean) => {
setToolbarVisibleState(visible);
localStorage.setItem(STORAGE_KEYS.TOOLBAR_VISIBLE, visible.toString());
}, []);

// Function to update default tool
const setDefaultTool = useCallback((tool: string) => {
setDefaultToolState(tool);
localStorage.setItem(STORAGE_KEYS.DEFAULT_TOOL, tool);
}, []);

// Update the global context value
const globalContextValue: GlobalConfigContextType = {
// Existing values
language,
setLanguage,
openaiApiKey,
setOpenaiApiKey,
loggingEnabled,
setLoggingEnabled: handleSetLoggingEnabled,
isGlobalConfigModalOpen,
setGlobalConfigModalOpen,

// New values
isToolbarVisible,
setToolbarVisible,
defaultTool,
setDefaultTool,
};

// ... rest of the component ...
}
```

This implementation:

1. Adds new types to the GlobalConfigContextType
2. Adds new storage keys for persisting the settings
3. Creates new state variables with default values
4. Adds setter functions that update both state and localStorage
5. Exposes the new values and setters through the context

The next step would be to update the ConfigModal component to expose these settings in the UI and then modify the Index component to use these settings.
Loading