diff --git a/.crush/logs/crush.log b/.crush/logs/crush.log new file mode 100644 index 0000000..f564d02 --- /dev/null +++ b/.crush/logs/crush.log @@ -0,0 +1,2 @@ +{"time":"2026-02-23T12:04:10.777456+07:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":55},"msg":"Fetching providers from Catwalk"} +{"time":"2026-02-23T12:04:11.177713+07:00","level":"INFO","source":{"function":"github.com/charmbracelet/crush/internal/config.(*catwalkSync).Get.func1","file":"github.com/charmbracelet/crush/internal/config/catwalk.go","line":63},"msg":"Catwalk providers not modified"} diff --git a/.opencode/plugins/entire.ts b/.opencode/plugins/entire.ts new file mode 100644 index 0000000..0c02bfd --- /dev/null +++ b/.opencode/plugins/entire.ts @@ -0,0 +1,133 @@ +// Entire CLI plugin for OpenCode +// Auto-generated by `entire enable --agent opencode` +// Do not edit manually — changes will be overwritten on next install. +// Requires Bun runtime (used by OpenCode's plugin system for loading ESM plugins). +import type { Plugin } from "@opencode-ai/plugin" + +export const EntirePlugin: Plugin = async ({ $, directory }) => { + const ENTIRE_CMD = "entire" + // Track seen user messages to fire turn-start only once per message + const seenUserMessages = new Set() + // Track current session ID for message events (which don't include sessionID) + let currentSessionID: string | null = null + // In-memory store for message metadata (role, tokens, etc.) + const messageStore = new Map() + + /** + * Pipe JSON payload to an entire hooks command (async). + * Errors are logged but never thrown — plugin failures must not crash OpenCode. + */ + async function callHook(hookName: string, payload: Record) { + try { + const json = JSON.stringify(payload) + await $`echo ${json} | ${ENTIRE_CMD} hooks opencode ${hookName}`.quiet().nothrow() + } catch { + // Silently ignore — plugin failures must not crash OpenCode + } + } + + /** + * Synchronous variant for hooks that fire near process exit (turn-end, session-end). + * `opencode run` breaks its event loop on the same session.status idle event that + * triggers turn-end. The async callHook would be killed before completing. + * Bun.spawnSync blocks the event loop, preventing exit until the hook finishes. + */ + function callHookSync(hookName: string, payload: Record) { + try { + const json = JSON.stringify(payload) + Bun.spawnSync(["sh", "-c", `${ENTIRE_CMD} hooks opencode ${hookName}`], { + cwd: directory, + stdin: new TextEncoder().encode(json + "\n"), + stdout: "ignore", + stderr: "ignore", + }) + } catch { + // Silently ignore — plugin failures must not crash OpenCode + } + } + + return { + event: async ({ event }) => { + switch (event.type) { + case "session.created": { + const session = (event as any).properties?.info + if (!session?.id) break + // Reset per-session tracking state when switching sessions. + if (currentSessionID !== session.id) { + seenUserMessages.clear() + messageStore.clear() + } + currentSessionID = session.id + await callHook("session-start", { + session_id: session.id, + }) + break + } + + case "message.updated": { + const msg = (event as any).properties?.info + if (!msg) break + // Store message metadata (role, time, tokens, etc.) + messageStore.set(msg.id, msg) + break + } + + case "message.part.updated": { + const part = (event as any).properties?.part + if (!part?.messageID) break + + // Fire turn-start on the first text part of a new user message + const msg = messageStore.get(part.messageID) + if (msg?.role === "user" && part.type === "text" && !seenUserMessages.has(msg.id)) { + seenUserMessages.add(msg.id) + const sessionID = msg.sessionID ?? currentSessionID + if (sessionID) { + await callHook("turn-start", { + session_id: sessionID, + prompt: part.text ?? "", + }) + } + } + break + } + + case "session.status": { + // session.status fires in both TUI and non-interactive (run) mode. + // session.idle is deprecated and not reliably emitted in run mode. + const props = (event as any).properties + if (props?.status?.type !== "idle") break + const sessionID = props?.sessionID + if (!sessionID) break + // Use sync variant: `opencode run` exits on the same idle event, + // so an async hook would be killed before completing. + callHookSync("turn-end", { + session_id: sessionID, + }) + break + } + + case "session.compacted": { + const sessionID = (event as any).properties?.sessionID + if (!sessionID) break + await callHook("compaction", { + session_id: sessionID, + }) + break + } + + case "session.deleted": { + const session = (event as any).properties?.info + if (!session?.id) break + seenUserMessages.clear() + messageStore.clear() + currentSessionID = null + // Use sync variant: session-end may fire during shutdown. + callHookSync("session-end", { + session_id: session.id, + }) + break + } + } + }, + } +} diff --git a/AGENTS.md b/AGENTS.md index 9619ce6..560a540 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,500 +1,52 @@ -# Agents Design Principles & Implementation Guide - -This project follows the **Carbon Design System** guidelines to ensure a consistent, accessible, and professional user interface. All new features and tools **MUST** adhere to these principles. - ---- - -## ⚠️ IMPORTANT: Check Tool Status Before Modifying - -**Before editing any tool component, ALWAYS check [TOOL_STATUS.md](./TOOL_STATUS.md)** to see if it's currently being refactored or already completed. - -This prevents: -- Accidentally modifying a tool already refactored with new patterns -- Conflicting with ongoing refactoring work -- Introducing outdated patterns into completed tools - -See [TOOL_STATUS.md](./TOOL_STATUS.md) for the current status of each tool. - ---- - -## 1. Design System & Theme -- **System**: [Carbon Design System](https://carbondesignsystem.com/) (`@carbon/react`). -- **Theme**: The application is wrapped in a Carbon `` provider. - - **Dark Theme (`g100`)** by default. - - Colors must use Carbon Usage Tokens (e.g., `var(--cds-layer)`, `var(--cds-text-primary)`). Do not use hardcoded hex values. - -## 2. Interaction & Layout Rules (Strict) - -### Tool Layout Structure -Every tool must follow this hierarchy: -1. **Header**: Tool Title (`

`) and Description (`

`). -2. **Controls**: A distinct row/area for options (selects, inputs) and primary actions (buttons). -3. **Workspace**: The main area, usually split 50/50 between Input and Output panes. - -### Layout Toggle (Horizontal/Vertical) -All tools with split-pane layouts **MUST** include a layout toggle button to allow users to switch between horizontal and vertical arrangements. - -**Implementation Pattern:** -```jsx -import useLayoutToggle from '../hooks/useLayoutToggle'; -import { ToolLayoutToggle } from '../components/ToolUI'; - -// In component: -const layout = useLayoutToggle({ - toolKey: 'unique-tool-key-layout', - defaultDirection: 'horizontal', - showToggle: true, - persist: true -}); - -// In ToolControls: -

- -
- -// On ToolSplitPane: - -``` - -**Requirements:** -- Place the toggle button at the end of the `ToolControls` area using `marginLeft: 'auto'` -- Use a unique `toolKey` for each tool to ensure independent persistence -- Always set `persist: true` to remember user's preference -- Update `ToolSplitPane` to dynamically adjust `columnCount` based on layout direction - -### Component Specifics - -#### Buttons -- **Location**: Place in the **Controls** area, distinct from utility options if possible, or clustered logically. -- **Spacing**: Multiple buttons on the same line MUST have spacing between them (gap: 1rem). -- **Consistency**: All buttons must match the theme. Primary actions use `kind="primary"`, secondary `kind="secondary"`, etc. - -#### Input/Output Panes (TextAreas) -- **Consistency**: Input and Output areas must look identical in structure. -- **Typography**: Use **Monospace** font for all data/code input/outputs. Same font size (`12px` or `14px`). -- **Height**: Input and Output panes should be the **same height** and fill the available vertical space (`height: 100%`). -- **Borders**: All text areas must have a visible border for better visibility. -- **Labels**: - - Must be present and consistent in casing (Title Case). -- **Copy Button**: - - MUST be placed **beside the label** (top-right of the pane header). - - MUST **always** be visible (do not hide on hover or empty state, though disabling on empty state is acceptable, showing it is preferred for consistency). - -#### Labels -- Use consistent typography for component labels (Carbon's label style). - -## 3. Reusable Components -Use the standardized components in `src/components/ToolUI.jsx` to enforce these rules automatically: -- `` -- ``: Wrapper for inputs and buttons. -- ``: The standardized Input/Output area with built-in Copy button support. - -## 4. Implementation Details -- **SCSS**: `src/index.scss` maps global variables. -- **Icons**: Use `@carbon/icons-react`. - -## 5. Testing Guidelines - -### Table-Driven Test Style (Mandatory) - -All Go tests **MUST** follow Go's recommended table-driven (table test) style. This provides clear structure, easy addition of new test cases, and consistent test organization. - -#### Required Structure: -```go -func TestConverter(t *testing.T) { - tests := []struct { - name string // Descriptive test case name - input string // Input data - method string // Method being tested - subMode string // Mode (Encode/Decode, Encrypt/Decrypt, etc.) - expected string // Expected output - expectErr bool // Whether an error is expected - }{ - {"Base64 Encode hello", "hello", "base64", "Encode", "aGVsbG8=", false}, - {"Base64 Decode aGVsbG8=", "aGVsbG8=", "base64", "Decode", "hello", false}, - {"Hex Encode", "hello", "hex", "Encode", "68656c6c6f", false}, - // Add more cases... - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - req := ConversionRequest{ - Input: tt.input, - Method: tt.method, - Config: map[string]interface{}{"subMode": tt.subMode}, - } - result, err := conv.Convert(req) - - if tt.expectErr { - if err == nil { - t.Errorf("Expected error but got none") - } - return - } - - if err != nil { - t.Errorf("Unexpected error: %v", err) - return - } - - if result != tt.expected { - t.Errorf("Expected '%s', got '%s'", tt.expected, result) - } - }) - } -} -``` - -#### Key Requirements: -- **Name field**: Every test case must have a descriptive `name` field -- **Slice of structs**: Use `[]struct{...}` to define all test cases -- **Iterate with range**: Use `for _, tc := range tests` -- **Subtests with t.Run**: Always use `t.Run(tc.name, func(t *testing.T) {...})` -- **Parallel execution**: When needed, use `tc := tc` capture and `t.Parallel()` - -### What NOT to Do: -❌ **Individual t.Run() calls** - Don't write separate `t.Run()` calls for each test case: -```go -// BAD - Don't do this -t.Run("Test 1", func(t *testing.T) { ... }) -t.Run("Test 2", func(t *testing.T) { ... }) -t.Run("Test 3", func(t *testing.T) { ... }) -``` - -✅ **Do this instead**: -```go -// GOOD - Table-driven -for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { ... }) -} -``` - -### Best Practices: -- **Clear case names**: Use descriptive names like `"AES Encrypt - simple text"` not `"test1"` -- **Deterministic setup**: Avoid global state, setup everything in the test function -- **Test both directions**: For bidirectional operations (encode/decode), test both ways -- **Edge cases**: Include empty strings, special characters, unicode, long text -- **Error cases**: Test invalid inputs and expect errors - -### Running Tests: -```bash -# Run all tests -go test ./internal/converter/... - -# Run with verbose output -go test ./internal/converter/... -v - -# Run specific test -go test ./internal/converter/... -run TestEncodingConverter -``` - ---- - -## 6. Backend Architecture & Patterns - -This project follows clean architecture principles with domain‑driven design (DDD) inspiration. The backend is organized into layers with clear separation of concerns. - -### Package Structure - -- **`internal/`** – Domain‑specific packages (e.g., `internal/jwt/`). These are private to the application and not importable outside. -- **`pkg/`** – Shared, reusable utilities (e.g., `pkg/encoding`, `pkg/validation`, `pkg/errors`). These are public and can be imported by other packages. (Previously organized under `pkg/shared/`; now flattened for simplicity.) -- **`*.go` in root** – Wails binding structs (e.g., `jwt_service.go`). Each tool that needs backend logic should have its own service file. - -### Domain Package Structure (Example: `internal/jwt/`) - -``` -internal/jwt/ -├── errors.go # Domain‑specific error types -├── token.go # Core domain models (Token, ValidationResult) with builder pattern -├── parser.go # Interface and implementation for parsing/verification -├── service.go # Service interface and implementation -└── dto.go # Data transfer objects matching frontend state -``` - -### Key Patterns - -1. **Interfaces First**: Define interfaces for major components (e.g., `Parser`, `JWTService`). -2. **Builder Pattern**: Use fluent builders for complex objects (see `Token.WithHeader()`, `ValidationResult.WithMessage()`). -3. **Error Mapping**: Convert library errors to domain errors using shared error types from `pkg/errors`. -4. **State Compatibility**: Backend response structures must exactly match frontend state (see `DecodeResponse`, `VerifyResponse` in `dto.go`). -5. **Wails Binding**: Create a separate service struct for each tool (e.g., `JWTService`) that implements `startup()` and exposes methods to the frontend. - -### Implementation Example (JWT Debugger) - -**Service Definition** (`jwt_service.go`): -```go -type JWTService struct { - ctx context.Context - svc jwt.JWTService -} - -func (j *JWTService) Decode(token string) (jwt.DecodeResponse, error) { - result, err := j.svc.Decode(token) - if err != nil { - return jwt.DecodeResponse{Error: err.Error()}, nil - } - return jwt.FromToken(result), nil -} -``` - -**Frontend Integration** (`JwtDebugger.jsx`): -```js -const response = await window.go.main.JWTService.Decode(state.token); -``` - -### Testing Backend Code - -All Go tests MUST follow the table‑driven style described in section 5. Example: - -```go -func TestDecode(t *testing.T) { - tests := []struct { - name string - token string - wantErr bool - }{ - {name: "valid token", token: "eyJ...", wantErr: false}, - {name: "empty token", token: "", wantErr: true}, - } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - // test logic - }) - } -} -``` - ---- - -## 7. Development Setup - -### Prerequisites -- **Bun** (>= 1.0) - Required for frontend dependencies -- **Go** (>= 1.22) -- **Wails CLI** (`go install github.com/wailsapp/wails/v2/cmd/wails@latest`) - -### Installation -```bash -# Clone the repository -git clone https://github.com/vuon9/devtoolbox.git -cd devtoolbox - -# Install dependencies (using Bun) -bun install -``` - -### Running the Application -- **Development mode** (hot reload): - ```bash - wails dev - ``` -- **Production build**: - ```bash - wails build - ``` - -The application will open in a native window. All tools work offline; no external API calls are required. - ---- - -## 8. Linting & Formatting - -### Frontend -- **ESLint**: Not currently configured. Consider adding `.eslintrc` and scripts. -- **Prettier**: Not currently configured. Consider adding `.prettierrc`. - -**Recommended**: Add linting and formatting scripts to `package.json`: -```json -"scripts": { - "lint": "eslint src --ext .js,.jsx", - "format": "prettier --write src/**/*.{js,jsx}" -} -``` - -Run these commands before committing: -```bash -bun run lint -bun run format -``` - -### Go -- **gofmt**: Format Go code with: - ```bash - gofmt -w . - ``` -- **govet**: Check for suspicious constructs: - ```bash - go vet ./... - ``` - ---- - -## 9. Adding a New Tool - -Follow this step‑by‑step guide to add a new tool component: - -1. **Create Component File** - - Create a new `.jsx` file in `src/pages/` (e.g., `MyNewTool.jsx`). - - Use the existing tool components as reference (e.g., `JwtDebugger.jsx`). - -2. **Implement the Tool** - - Import Carbon components and `ToolUI` helpers. - - Use `useReducer` for state management (not multiple `useState` hooks). - - Use `useCallback` for memoized functions. - - Follow the **Tool Layout Structure** (Header → Controls → Workspace). - - Use `ToolHeader`, `ToolControls`, `ToolPane`, `ToolSplitPane` from `ToolUI.jsx`. - - Ensure input/output panes are symmetrical, have monospace fonts, and include copy buttons. - -3. **Add Route** - - Open `src/App.jsx`. - - Import your new component. - - Add the component to the `renderTool()` switch statement: - ```jsx - case 'my-new-tool': return ; - ``` - -4. **Update Sidebar** - - Open `src/components/Sidebar.jsx`. - - Add an entry to the `tools` array: - ```jsx - { id: 'my-new-tool', name: 'My New Tool', icon: '🛠️' } - ``` - -5. **Test the Tool** - - Run `wails dev` to verify the tool works correctly. - - Ensure UI matches Carbon Design System and all interaction rules are followed. - -6. **Update Documentation** - - Add the tool to the feature table in `README.md`. - - Update `TOOL_STATUS.md` with the new tool (status: 🟢 Done). - ---- - -## 9b. Consolidating/Merging Tools (Unified Tools Pattern) - -When creating a unified tool that replaces multiple existing tools (e.g., `CodeFormatter` replacing `JsonFormatter`, `SqlFormatter`, etc.), follow these additional steps: - -### Implementation Steps - -1. **Create Unified Tool First** - - Build the new unified tool following the standard tool creation process - - Ensure it covers ALL features of the tools it replaces - - Test thoroughly before removing old tools - -2. **Update All Registrations** - - Add route in `App.jsx` for the new unified tool - - Add entry in `Sidebar.jsx` for navigation - - Register backend service in `main.go` and `server.go` - -3. **Documentation Updates** - - Update `README.md` to reflect the consolidated tool (remove entries for replaced tools, add unified tool entry) - - Update `TOOL_STATUS.md`: - - Mark new unified tool as 🟢 Done - - Optionally add notes about which tools it replaces - - Consider adding a note in AGENTS.md about this consolidation pattern - -4. **Testing the Migration** - - Verify all functionality from old tools works in the unified tool - - Test sidebar navigation and routing - - Ensure state persistence works correctly - -### Tool Removal Process (After Migration is Complete) - -Once the unified tool is fully functional and tested: - -1. **Remove Old Tool Components** - - Delete old component files from `src/pages/` - - Remove imports from `App.jsx` - - Remove entries from `Sidebar.jsx` - - Clean up any unused backend services - -2. **Update TOOL_STATUS.md** - - Remove entries for deprecated tools, OR - - Mark them as "Replaced by [UnifiedTool]" with strikethrough - -3. **Clean Up Backend (if applicable)** - - Remove unused service files from root directory - - Remove unused internal packages if no longer needed - - Update `main.go` to remove old service bindings - -### Example: CodeFormatter Consolidation - -**Replaced Tools:** -- `JsonFormatter` → Now part of CodeFormatter with jq filter support -- `SqlFormatter` → Now part of CodeFormatter with SQL formatting -- (Future: XML tools, CSS tools, etc.) - -**Migration Notes:** -- CodeFormatter adds new capabilities (jq filters, XPath, CSS selectors) not in original tools -- State persistence moved to unified storage key -- Backend service supports 6+ format types with extensible architecture - ---- - -## 10. Refactoring a Tool - -Refer to **[TOOL_STATUS.md](./TOOL_STATUS.md)** for the current status of each tool. **Always check this file before modifying any tool component.** - -### Refactoring Process -1. **Check Status**: If the tool is 🟢 Done, no changes are needed unless fixing bugs. If 🔴 Not Started, you may refactor. -2. **Update Status**: Change the tool's status to 🟡 In Progress with a note and timestamp. -3. **Follow Checklist**: Use the **Refactoring Checklist** in `TOOL_STATUS.md` to ensure all requirements are met: - - [ ] Uses **Carbon Design System** components (`@carbon/react`) - - [ ] All colors use `var(--cds-*)` tokens, no hardcoded hex values - - [ ] Implements **useReducer** for state management (not multiple useState hooks) - - [ ] Uses **useCallback** for memoized functions - - [ ] Follows **DRY principle** – no duplicated components/logic - - [ ] Has proper **ToolHeader** with title and description - - [ ] Input/Output panes are symmetrical and use **Carbon TextArea** - - [ ] All buttons properly spaced (gap: 1rem) - - [ ] Copy buttons present on all output/data panes - - [ ] Monospace font for data (`'IBM Plex Mono', monospace`) - - [ ] Proper flex layout for responsive sizing - - [ ] No unused imports or variables - - [ ] Code compiles without errors or warnings -4. **Complete Refactoring**: After all checklist items are satisfied, change the status to 🟢 Done and add completion date. - ---- - -## 11. Agent‑Specific Guidelines - -These guidelines are intended for AI assistants (like opencode) working on this repository. - -### Before Starting Work -1. **Read `AGENTS.md`** – Understand the design principles and implementation rules. -2. **Check `TOOL_STATUS.md`** – Never modify a tool that is already 🟢 Done or 🟡 In Progress unless explicitly instructed. -3. **Examine existing code** – Look at recently refactored tools (e.g., `JwtDebugger.jsx` and its Go backend in `internal/jwt/`) to see the expected patterns. - -### While Implementing -1. **Follow Carbon Design System** – Use `@carbon/react` components, Carbon tokens, and the provided `ToolUI` helpers. -2. **State Management** – Prefer `useReducer` over multiple `useState` hooks for complex state. -3. **Performance** – Use `useCallback` for event handlers and `React.memo` for expensive components when appropriate. -4. **DRY** – Reuse existing components and utilities; avoid duplicating logic. -5. **UI Consistency** – Ensure input/output panes are identical in height, font, borders, and always show copy buttons. -6. **Code Quality** – Remove unused imports, variables, and debug logs before finishing. - -### Before Finishing -1. **Run linting & formatting** – Execute any available lint/format commands (see section 8). -2. **Test the tool** – Verify functionality with `wails dev`. -3. **Update `TOOL_STATUS.md`** – Update the tool's status and add completion notes (mark as 🟢 Done when complete). -4. **Update `README.md`** – **REQUIRED: Whenever TOOL_STATUS.md is updated, README.md MUST also be updated to ensure consistency**: - - Add new tools to the feature table - - Remove deprecated tools - - Update descriptions if features changed - - Keep the tool count/feature list in sync - - **This is mandatory** - never update TOOL_STATUS.md without checking/updating README.md -5. **Commit changes** – Use descriptive commit messages that reference the tool name and changes made. - -### Important Notes -- **Never commit secrets** – Avoid committing `.env`, credentials, or any sensitive data. -- **Respect existing conventions** – Follow the project’s code style, naming, and file structure. -- **Ask for clarification** – If unsure about any requirement, ask the user before proceeding. - ---- - -*Last updated: 2026‑01‑31* +Here are principles and guidelines for developing tools and agents in this project: + +- A short, practical reference for contributors and automation agents. +- Focus: consistent UI, maintainable backend patterns, and a simple development workflow. + - Use the Carbon Design System and Carbon tokens for colors and theming. Avoid hardcoded color values. + - Default visual tone is dark; follow the project's theme provider. + - Prefer small, reusable components to maintain consistency. + +## Tool layout +- Tools must present three areas: + - Header (title + short purpose) + - Controls (options + actions) + - Workspace (content panes). +- Optional: Workspace commonly uses a split layout; provide a way for users to switch orientations and persist their preference. Please think first before deciding and confirm in case of doubt. +- Controls should be clearly separated from utility options. +- Front-end code must be organized into components and helpers that reflect the UI structure, with clear naming and separation of concerns. + +## Component rules (high level) +- Buttons: group logically, use consistent visual hierarchy (primary vs secondary). +- Input/output panes: visually identical, monospace for data/code, equal heights, visible borders, and accessible labels. +- Copy actions: make copy/export controls discoverable and consistently placed near pane headers. + +## Reuse & consistency +- Centralize shared UI patterns into common helpers/components. +- Prefer composition over duplication—reuse helpers rather than reimplementing layout/controls. +- Keep styles and tokens centralized so changes propagate cleanly. + +## Backend architecture (conceptual) +- Follow layered design: domain logic isolated from transport/bindings. +- Define clear interfaces for major components and keep implementations testable and replaceable. +- Map external/library errors into domain-level errors; surface user-facing messages that are actionable. +- Ensure backend data shapes align with frontend expectations. + +## Testing & quality +- Tests should be deterministic, well-named, and cover edge and error cases. +- Use table-driven style for data-driven behavior where appropriate. +- Run formatting and vetting tools as part of local checks before committing. + +## Developer workflow (summary) +- Keep local setup lightweight: install frontend and backend deps, run the dev server, iterate. +- Use centralized scripts for linting and formatting. +- Run the app locally to verify UI consistency and interactions. + +## Collaboration & commits +- Keep commits focused and descriptive. +- Do not commit secrets or credentials. +- If unsure about removing or changing conventions, discuss before large refactors. + +## Final note +- This document is a concise set of rules and intent. For implementation details and examples, read the code and shared UI helpers; the code is the authoritative source. +- Keep the guide short and actionable; prefer making the code easy to understand over expanding this file. diff --git a/TOOL_STATUS.md b/TOOL_STATUS.md deleted file mode 100644 index 5d664a4..0000000 --- a/TOOL_STATUS.md +++ /dev/null @@ -1,44 +0,0 @@ -# Tool Development Status - -This document tracks the refactoring and development status of each tool component. **Always check this before modifying tool code** to avoid conflicts with ongoing refactoring efforts. - -## Status Legend - -- 🟢 **Done** - Tool fully refactored, uses Carbon Design System, follows all guidelines -- 🟡 **In Progress** - Tool is being refactored, use caution before modifying -- 🔴 **Not Started** - Tool uses legacy patterns, needs full refactoring - ---- - -## Tool Status - -| Tool | Status | Notes | Last Updated | -|------|--------|-------|--------------| -| JwtDebugger | 🟢 Done | Uses component abstraction system (ToolLayout, ToolTextArea, ToolInputGroup), toggleable layout, consistent button styling with icons (MagicWand, Security, Code), enhanced tabs (custom mode tabs, improved JSON/Claims tabs), resizable textareas with constraints, proper error handling | Completed 2026-01-25 | -| **TextConverter** | 🟢 Done | Unified tool with 45+ algorithms across 5 categories (encrypt, encode, escape, hash, convert). Features: Common Tags (Quick Select), Base64 Image Preview, All Hashes view, Smart ConfigurationPane, 5 Escape methods. Backend: hierarchical structure with 83 comprehensive tests. Phase 2 & 3 complete. Replaces: TextBasedConverter | Completed 2026-01-31 | -| **StringUtilities** | 🟡 In Progress | Consolidated tool combining LineSortDedupe, StringCaseConverter, and StringInspector. Features: Tab navigation (Sort/Dedupe, Case Converter, Inspector), shared input state, layout toggle, Carbon Design System compliance. | Updated 2026-01-31 | -| **NumberConverter** | 🟢 Done | Converted from NumberBaseConverter. Features: 4-pane layout (Decimal, Hex, Octal, Binary), bidirectional conversion, layout toggle, active field highlighting, Carbon Design System compliance. | Completed 2026-01-31 | -| BarcodeGenerator | 🟢 Done | Multi-standard barcode generator (QR, EAN-13, EAN-8, Code128, Code39). Features: configurable size, error correction levels for QR, client-side validation, download button. | Completed 2026-01-31 | -| **DataGenerator** | 🟢 Done | Template-based mock data generator with Faker integration. Features: 10 built-in presets (UUID, ULID, Random String, Lorem Ipsum, User Profile, E-commerce Product, API Response, SQL Insert, Log Entries, Credit Card), batch generation (10-1000 records), multiple output formats (JSON, XML, CSV, YAML), comprehensive help documentation with 4 tabs (Quick Start, Syntax, Faker Reference, Examples). Backend: Go templates + gofakeit library with 80+ faker functions. Replaces: RandomStringGenerator, UuidGenerator, LoremIpsumGenerator | Completed 2026-01-31 | -| **CodeFormatter** | 🟢 Done | Unified code formatting tool supporting JSON (with jq filters), XML (with XPath), HTML (with CSS selectors), SQL, CSS, and JavaScript. Features: format/minify modes, filter/query support for structured data, auto-format on input change, persistent state. Backend: Go with gojq library for jq support. Replaces: JsonFormatter, SqlFormatter | Completed 2026-01-31 | -| **ColorConverter** | 🟢 Done | Comprehensive color conversion tool with visual picker and eyedropper support. Features: 11 programming languages (CSS, Swift, .NET, Java, Android, Obj-C, Flutter, Unity, React Native, OpenGL, SVG), 5 color formats (HEX, RGB, HSL, HSV, CMYK), color history with 10 recent colors, random color generator, copy-to-clipboard for all code snippets. Uses Carbon Tabs for language selection. | Completed 2026-02-01 | -| **CronJobParser** | 🟢 Done | Refactored to follow Carbon Design System. Features: Split-pane layout, 8 common examples in clickable tiles, real-time parsing, large centered output display, layout toggle. | Completed 2026-01-31 | -| **RegExpTester** | 🟢 Done | Enhanced with live highlighting. Features: Unified regex input group with visual connection, expandable auto-resizing textarea (1-10 lines), theme-aware scrollbar, flags popover accessible via flags input, live match highlighting with group colors in test string and match details, hover tooltips, split-pane layout, copy full regex button, layout toggle. | Completed 2026-02-11 | -| **TextDiffChecker** | 🟡 In Progress | Refactored with enhanced features. Features: Diff mode switcher (Lines/Words/Chars), auto-compare on input change, Clear button, improved diff view with color coding, layout toggle. | Updated 2026-01-31 | -| **DateTimeConverter** | 🟢 Done | Complete redesign as unified DateTime Converter. All features on single screen - no tabs. Client-side only (no backend dependency). Features: Auto-detect input format (Unix timestamps: s/ms/μs/ns, ISO dates, SQL dates, US/EU formats), Quick presets (Now, Start/End of Day, Tomorrow, Yesterday, Next Week, Unix Epoch), Output format selector (ISO, RFC, SQL, US, EU, Compact), Timezone support, Main result display with relative time, All formats grid with copy buttons, Toggle-able sections: Visual Widgets (Calendar + Analog Clock), Time Calculator (Date A vs B with delta), Batch Converter (multi-line input with table results), Timezone Comparison (6 major cities), History persistence (localStorage, last 20), URL share support (?ts=). Unified, user-friendly interface designed for real-world datetime conversion needs. | Completed 2026-02-01 | - ---- - -## How to Update This File - -When starting work on a tool: - -1. Change status from 🔴 to 🟡 and add your name/timestamp -2. Add specific notes about what you're refactoring -3. When complete, change to 🟢 and add completion date - -Example: - -``` -| YourTool | 🟡 In Progress | Refactoring state management, DRY components | Started 2025-12-13 | -``` diff --git a/frontend/.prettierignore b/frontend/.prettierignore new file mode 100644 index 0000000..7027002 --- /dev/null +++ b/frontend/.prettierignore @@ -0,0 +1,7 @@ +node_modules/ +dist/ +build/ +coverage/ +*.min.js +*.min.css +src/generated/ diff --git a/frontend/.prettierrc b/frontend/.prettierrc new file mode 100644 index 0000000..1f4c4bb --- /dev/null +++ b/frontend/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "printWidth": 100 +} diff --git a/frontend/bun.lock b/frontend/bun.lock index 69877bd..9e6ddad 100644 --- a/frontend/bun.lock +++ b/frontend/bun.lock @@ -4,9 +4,9 @@ "": { "name": "frontend", "dependencies": { - "@carbon/icons-react": "^11.71.0", - "@carbon/react": "^1.97.0", - "@carbon/styles": "^1.96.0", + "@carbon/icons-react": "^11.76.0", + "@carbon/react": "^1.102.0", + "@carbon/styles": "^1.101.0", "@wailsio/runtime": "^3.0.0-alpha.79", "cronstrue": "^3.9.0", "diff": "^8.0.2", @@ -28,6 +28,7 @@ "@types/react": "^18.0.17", "@types/react-dom": "^18.0.6", "@vitejs/plugin-react": "^4.0.0", + "prettier": "^3.5.3", "vite": "^5.4.21", }, }, @@ -73,29 +74,29 @@ "@babel/types": ["@babel/types@7.28.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg=="], - "@carbon/colors": ["@carbon/colors@11.46.0", "", { "dependencies": { "@ibm/telemetry-js": "^1.5.0" } }, "sha512-YL4BH2hxHkUT0+wMn8cO3sYN7rb9Nnp7rGttoblM0iTy83n/urwRPcxudifRwJLtASQpravCyLHdIC9WnTtIAA=="], + "@carbon/colors": ["@carbon/colors@11.48.0", "", { "dependencies": { "@ibm/telemetry-js": "^1.5.0" } }, "sha512-fJfgGBlzKugSS32z9/yI+XrSgiZttrFPBcsqrfxMjWAIPCRke1l3nypfL0AenetVof95dE38KA09i08uK9Zl2Q=="], - "@carbon/feature-flags": ["@carbon/feature-flags@0.32.0", "", { "dependencies": { "@ibm/telemetry-js": "^1.5.0" } }, "sha512-a1rFplSEFPwJ4ZsuwvOaKHgoLqPNhjCJdWY6VTgCoytRZqtgYWqwYFEqQkm9/f1mX1lHr6oK/eBpAcmi0Izuvg=="], + "@carbon/feature-flags": ["@carbon/feature-flags@1.0.0", "", { "dependencies": { "@ibm/telemetry-js": "^1.5.0" } }, "sha512-1WNmR2TFXAmt1je5B/DahEYV7hOrheAxj7djuQrQB8qomPQyxvZ4vaIK5rARUp7HK6HQndpvCD4+IEvagI/Bmg=="], - "@carbon/grid": ["@carbon/grid@11.49.0", "", { "dependencies": { "@carbon/layout": "^11.47.0", "@ibm/telemetry-js": "^1.5.0" } }, "sha512-zZfj/sbwJpXboduVFNUXUdV6LmsEH39fNQQMye4V+788sdvs+ErO8L3onBZFpsek5gI4ebwjpWJu2g5szu2+kQ=="], + "@carbon/grid": ["@carbon/grid@11.51.0", "", { "dependencies": { "@carbon/layout": "^11.49.0", "@ibm/telemetry-js": "^1.5.0" } }, "sha512-5x4ri8GCBjckxd7/QuJzWwdcoCdhukeOcZ3ASrYnMY8IYEo+7NzBjIIFA4M7B5jsT2zd29uIIZqcTHcPg+1L8w=="], - "@carbon/icon-helpers": ["@carbon/icon-helpers@10.71.0", "", { "dependencies": { "@ibm/telemetry-js": "^1.5.0" } }, "sha512-T6KcxkNIa609jPC+8A7u5husSY+mH60lCNNa3ivcOyuREoVYHwnieM7GIECigF/oaGaF5eBzrxYFx2+8mLRk1A=="], + "@carbon/icon-helpers": ["@carbon/icon-helpers@10.73.0", "", { "dependencies": { "@ibm/telemetry-js": "^1.5.0" } }, "sha512-Grn/QxHZfSOdXp/WBadegVfq1LT96QwX9b977dqMU5qmxp6cxKqUGvV1oqs6GiBacKoQFrH2xgbKwlcecgSHfA=="], - "@carbon/icons-react": ["@carbon/icons-react@11.74.0", "", { "dependencies": { "@carbon/icon-helpers": "^10.71.0", "@ibm/telemetry-js": "^1.5.0", "prop-types": "^15.8.1" }, "peerDependencies": { "react": ">=16" } }, "sha512-tP/ZwM3e86zDm/8mup1NoObdaBl2xqZlroWP/Z1PQ9bCYOOFelR6r34aObWiDBJVpKb5YwwZWYUrl+/98fmDRQ=="], + "@carbon/icons-react": ["@carbon/icons-react@11.76.0", "", { "dependencies": { "@carbon/icon-helpers": "^10.73.0", "@ibm/telemetry-js": "^1.5.0", "prop-types": "^15.8.1" }, "peerDependencies": { "react": ">=16" } }, "sha512-FsRlufW8lcdEX/Vj0NpdloBDPmXGRCIaD6ENhYt0f42zJncs6OqNQ58plqNteHg/JMQAdA+pP8f5tSkopNhRRg=="], - "@carbon/layout": ["@carbon/layout@11.47.0", "", { "dependencies": { "@ibm/telemetry-js": "^1.5.0" } }, "sha512-2XR4TVp3uf2IB0WdoZuDcBbc9C8EN/JvZAw9BdHJ3njng8FlUAQUkTFvfoUsJl10868rqA6YeClCElBS4BHofg=="], + "@carbon/layout": ["@carbon/layout@11.49.0", "", { "dependencies": { "@ibm/telemetry-js": "^1.5.0" } }, "sha512-eT/G2o7sF80r5r8NJSDuLTQmVMr1u7VjQEkANVeaLg366VF5q36tCKgbs6kzFgJPEZhifonajIp27cS+gfylvQ=="], - "@carbon/motion": ["@carbon/motion@11.40.0", "", { "dependencies": { "@ibm/telemetry-js": "^1.5.0" } }, "sha512-QjvjMcC3G289GKYDvrf5dDuyol7SXm0TYaFltx+AkJdU6fptDCJ/qjUL5SdVrsLse3jFuI8rada9tRAL5xHS1g=="], + "@carbon/motion": ["@carbon/motion@11.42.0", "", { "dependencies": { "@ibm/telemetry-js": "^1.5.0" } }, "sha512-FYBBMnYanddsxGilGSM8/8u0HXLY1hpfbtgpdWCsjUXtxZLvBHYKPbStJWBkvmDuwfAxeweS1xEFCYNIYIzNGA=="], - "@carbon/react": ["@carbon/react@1.100.0", "", { "dependencies": { "@babel/runtime": "^7.27.3", "@carbon/feature-flags": ">=0.32.0", "@carbon/icons-react": "^11.74.0", "@carbon/layout": "^11.47.0", "@carbon/styles": "^1.99.0", "@carbon/utilities": "^0.15.0", "@floating-ui/react": "^0.27.4", "@ibm/telemetry-js": "^1.5.0", "classnames": "2.5.1", "copy-to-clipboard": "^3.3.1", "downshift": "9.0.10", "es-toolkit": "^1.27.0", "flatpickr": "4.6.13", "invariant": "^2.2.3", "prop-types": "^15.8.1", "react-fast-compare": "^3.2.2", "tabbable": "^6.2.0" }, "peerDependencies": { "react": "^16.8.6 || ^17.0.1 || ^18.2.0 || ^19.0.0", "react-dom": "^16.8.6 || ^17.0.1 || ^18.2.0 || ^19.0.0", "react-is": "^16.13.1 || ^17.0.2 || ^18.3.1 || ^19.0.0", "sass": "^1.33.0" } }, "sha512-QlJ/bqiQn3fF3EX1YfVN3+zYvbqiGuMULtsI+wtuMaoEOJcR9FBwUYSP4w7lXTCxQ7WkB/wTLrekVcGgRoNquQ=="], + "@carbon/react": ["@carbon/react@1.102.0", "", { "dependencies": { "@babel/runtime": "^7.27.3", "@carbon/feature-flags": "^1.0.0", "@carbon/icons-react": "^11.76.0", "@carbon/layout": "^11.49.0", "@carbon/styles": "^1.101.0", "@carbon/utilities": "^0.16.0", "@floating-ui/react": "^0.27.4", "@ibm/telemetry-js": "^1.5.0", "classnames": "2.5.1", "copy-to-clipboard": "^3.3.1", "downshift": "9.0.10", "es-toolkit": "^1.27.0", "flatpickr": "4.6.13", "invariant": "^2.2.3", "prop-types": "^15.8.1", "react-fast-compare": "^3.2.2", "tabbable": "^6.2.0" }, "peerDependencies": { "react": "^16.8.6 || ^17.0.1 || ^18.2.0 || ^19.0.0", "react-dom": "^16.8.6 || ^17.0.1 || ^18.2.0 || ^19.0.0", "react-is": "^16.13.1 || ^17.0.2 || ^18.3.1 || ^19.0.0", "sass": "^1.33.0" } }, "sha512-zs91aXKFQmQh45byj8hPhp+mY1OItxrnC3HLjVwSlJ/qjRpTdsJH9pCocbwL7tonkMI5/LR6vgscrYeINa22Og=="], - "@carbon/styles": ["@carbon/styles@1.99.0", "", { "dependencies": { "@carbon/colors": "^11.46.0", "@carbon/feature-flags": ">=0.32.0", "@carbon/grid": "^11.49.0", "@carbon/layout": "^11.47.0", "@carbon/motion": "^11.40.0", "@carbon/themes": "^11.67.0", "@carbon/type": "^11.53.0", "@ibm/plex": "6.0.0-next.6", "@ibm/plex-mono": "1.1.0", "@ibm/plex-sans": "1.1.0", "@ibm/plex-sans-arabic": "1.1.0", "@ibm/plex-sans-devanagari": "1.1.0", "@ibm/plex-sans-hebrew": "1.1.0", "@ibm/plex-sans-thai": "1.1.0", "@ibm/plex-sans-thai-looped": "1.1.0", "@ibm/plex-serif": "1.1.0", "@ibm/telemetry-js": "^1.5.0" }, "peerDependencies": { "sass": "^1.33.0" }, "optionalPeers": ["sass"] }, "sha512-71iypyzR97h6Z94XRZyel3IEo4+n9TRylKdsYUJASNs7GNIjsIBlwKRn+upUktsyWVNTV1iQ9uzo3UkFcRiEFQ=="], + "@carbon/styles": ["@carbon/styles@1.101.0", "", { "dependencies": { "@carbon/colors": "^11.48.0", "@carbon/feature-flags": "^1.0.0", "@carbon/grid": "^11.51.0", "@carbon/layout": "^11.49.0", "@carbon/motion": "^11.42.0", "@carbon/themes": "^11.69.0", "@carbon/type": "^11.55.0", "@ibm/plex": "6.0.0-next.6", "@ibm/plex-mono": "1.1.0", "@ibm/plex-sans": "1.1.0", "@ibm/plex-sans-arabic": "1.1.0", "@ibm/plex-sans-devanagari": "1.1.0", "@ibm/plex-sans-hebrew": "1.1.0", "@ibm/plex-sans-thai": "1.1.0", "@ibm/plex-sans-thai-looped": "1.1.0", "@ibm/plex-serif": "1.1.0", "@ibm/telemetry-js": "^1.5.0" }, "peerDependencies": { "sass": "^1.33.0" }, "optionalPeers": ["sass"] }, "sha512-1MaThegyxYlsYTO331d2GEc8Ney8jwKvmxKGTqg/kZUS0K/sCJ6itnm+P/VlvDzlOwGVLyzDJ5xGyKMnThwOSw=="], - "@carbon/themes": ["@carbon/themes@11.67.0", "", { "dependencies": { "@carbon/colors": "^11.46.0", "@carbon/layout": "^11.47.0", "@carbon/type": "^11.53.0", "@ibm/telemetry-js": "^1.5.0", "color": "^4.0.0" } }, "sha512-sCjmwxvM7nUdsDPef9g2v07Motvd4EYZJJqJyklMfhm9ZJ1oUfwecpW8rLzXylDsOBhrX9s1oCKWG/JqZF3kig=="], + "@carbon/themes": ["@carbon/themes@11.69.0", "", { "dependencies": { "@carbon/colors": "^11.48.0", "@carbon/layout": "^11.49.0", "@carbon/type": "^11.55.0", "@ibm/telemetry-js": "^1.5.0", "color": "^4.0.0" } }, "sha512-4Fh0N5vNVKwKLN/Mpmq/H48sfh8yJufCyjHX81CiC3G5wkzJJH1RJVbabp9vJLs0F2OEJhqpn3uvSsUBvNyDDg=="], - "@carbon/type": ["@carbon/type@11.53.0", "", { "dependencies": { "@carbon/grid": "^11.49.0", "@carbon/layout": "^11.47.0", "@ibm/telemetry-js": "^1.5.0" } }, "sha512-x3GeJrkvM8wdpBwYbRr6jUsmR2wSRVbIxmPl7kamSFih32+czp7xpt/frG02EAY5xgaEk3N9YCNYspwco42raA=="], + "@carbon/type": ["@carbon/type@11.55.0", "", { "dependencies": { "@carbon/grid": "^11.51.0", "@carbon/layout": "^11.49.0", "@ibm/telemetry-js": "^1.5.0" } }, "sha512-VKSJ+TV/J2hdFkCqRuBqUJhtNIOG3BJCOEHv0L+bfrFk82mksnx59hsBtJKpnsgsZ9er+1e8hkZPqqo8dHRHvg=="], - "@carbon/utilities": ["@carbon/utilities@0.15.0", "", { "dependencies": { "@ibm/telemetry-js": "^1.6.1", "@internationalized/number": "^3.6.1" } }, "sha512-bwneNtLk8khoSIsilr6fBl115BMBrCMqxo/LjwAYiA+GiHes4URC4QYUihg+Ida5bCDpMixDx3RI9IW1UodXLQ=="], + "@carbon/utilities": ["@carbon/utilities@0.16.0", "", { "dependencies": { "@ibm/telemetry-js": "^1.6.1", "@internationalized/number": "^3.6.1" } }, "sha512-lEYSOpD8Dfh9NJ00uNSORcJ2Bl4+UugM11110SBpbFyes4bWSQkSoRLqoIfV2f1WwFBVDyGXV08O3FaWUgQk3w=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], @@ -471,6 +472,8 @@ "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], + "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], "proto-list": ["proto-list@1.2.4", "", {}, "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="], diff --git a/frontend/index.html b/frontend/index.html index dc6ba24..0d44cfd 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1,15 +1,13 @@ - + - - + DevToolbox - + - +
- - - \ No newline at end of file + + diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..a8f717e --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,2257 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "@carbon/icons-react": "^11.71.0", + "@carbon/react": "^1.97.0", + "@carbon/styles": "^1.96.0", + "@wailsio/runtime": "^3.0.0-alpha.79", + "cronstrue": "^3.9.0", + "diff": "^8.0.2", + "js-beautify": "^1.15.4", + "js-yaml": "^4.1.1", + "jwt-decode": "^4.0.0", + "marked": "^17.0.1", + "papaparse": "^5.5.3", + "php-serialize": "^5.1.3", + "qrcode": "^1.5.4", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.96.0", + "sql-formatter": "^15.6.11", + "ulid": "^3.0.2", + "xml-formatter": "^3.6.7" + }, + "devDependencies": { + "@types/react": "^18.0.17", + "@types/react-dom": "^18.0.6", + "@vitejs/plugin-react": "^4.0.0", + "prettier": "^3.5.3", + "vite": "^5.4.21" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@carbon/colors": { + "version": "11.46.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@ibm/telemetry-js": "^1.5.0" + } + }, + "node_modules/@carbon/feature-flags": { + "version": "0.32.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@ibm/telemetry-js": "^1.5.0" + } + }, + "node_modules/@carbon/grid": { + "version": "11.49.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@carbon/layout": "^11.47.0", + "@ibm/telemetry-js": "^1.5.0" + } + }, + "node_modules/@carbon/icon-helpers": { + "version": "10.71.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@ibm/telemetry-js": "^1.5.0" + } + }, + "node_modules/@carbon/icons-react": { + "version": "11.74.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@carbon/icon-helpers": "^10.71.0", + "@ibm/telemetry-js": "^1.5.0", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "node_modules/@carbon/layout": { + "version": "11.47.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@ibm/telemetry-js": "^1.5.0" + } + }, + "node_modules/@carbon/motion": { + "version": "11.40.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@ibm/telemetry-js": "^1.5.0" + } + }, + "node_modules/@carbon/react": { + "version": "1.100.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.27.3", + "@carbon/feature-flags": ">=0.32.0", + "@carbon/icons-react": "^11.74.0", + "@carbon/layout": "^11.47.0", + "@carbon/styles": "^1.99.0", + "@carbon/utilities": "^0.15.0", + "@floating-ui/react": "^0.27.4", + "@ibm/telemetry-js": "^1.5.0", + "classnames": "2.5.1", + "copy-to-clipboard": "^3.3.1", + "downshift": "9.0.10", + "es-toolkit": "^1.27.0", + "flatpickr": "4.6.13", + "invariant": "^2.2.3", + "prop-types": "^15.8.1", + "react-fast-compare": "^3.2.2", + "tabbable": "^6.2.0" + }, + "peerDependencies": { + "react": "^16.8.6 || ^17.0.1 || ^18.2.0 || ^19.0.0", + "react-dom": "^16.8.6 || ^17.0.1 || ^18.2.0 || ^19.0.0", + "react-is": "^16.13.1 || ^17.0.2 || ^18.3.1 || ^19.0.0", + "sass": "^1.33.0" + } + }, + "node_modules/@carbon/styles": { + "version": "1.99.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@carbon/colors": "^11.46.0", + "@carbon/feature-flags": ">=0.32.0", + "@carbon/grid": "^11.49.0", + "@carbon/layout": "^11.47.0", + "@carbon/motion": "^11.40.0", + "@carbon/themes": "^11.67.0", + "@carbon/type": "^11.53.0", + "@ibm/plex": "6.0.0-next.6", + "@ibm/plex-mono": "1.1.0", + "@ibm/plex-sans": "1.1.0", + "@ibm/plex-sans-arabic": "1.1.0", + "@ibm/plex-sans-devanagari": "1.1.0", + "@ibm/plex-sans-hebrew": "1.1.0", + "@ibm/plex-sans-thai": "1.1.0", + "@ibm/plex-sans-thai-looped": "1.1.0", + "@ibm/plex-serif": "1.1.0", + "@ibm/telemetry-js": "^1.5.0" + }, + "peerDependencies": { + "sass": "^1.33.0" + }, + "peerDependenciesMeta": { + "sass": { + "optional": true + } + } + }, + "node_modules/@carbon/themes": { + "version": "11.67.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@carbon/colors": "^11.46.0", + "@carbon/layout": "^11.47.0", + "@carbon/type": "^11.53.0", + "@ibm/telemetry-js": "^1.5.0", + "color": "^4.0.0" + } + }, + "node_modules/@carbon/type": { + "version": "11.53.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@carbon/grid": "^11.49.0", + "@carbon/layout": "^11.47.0", + "@ibm/telemetry-js": "^1.5.0" + } + }, + "node_modules/@carbon/utilities": { + "version": "0.15.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@ibm/telemetry-js": "^1.6.1", + "@internationalized/number": "^3.6.1" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.4", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.5", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.4", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.27.17", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.7", + "@floating-ui/utils": "^0.2.10", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.7", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.5" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "license": "MIT" + }, + "node_modules/@ibm/plex": { + "version": "6.0.0-next.6", + "license": "OFL-1.1", + "engines": { + "node": ">=14" + } + }, + "node_modules/@ibm/plex-mono": { + "version": "1.1.0", + "hasInstallScript": true, + "license": "OFL-1.1", + "dependencies": { + "@ibm/telemetry-js": "^1.6.1" + } + }, + "node_modules/@ibm/plex-sans": { + "version": "1.1.0", + "hasInstallScript": true, + "license": "OFL-1.1", + "dependencies": { + "@ibm/telemetry-js": "^1.6.1" + } + }, + "node_modules/@ibm/plex-sans-arabic": { + "version": "1.1.0", + "hasInstallScript": true, + "license": "OFL-1.1", + "dependencies": { + "@ibm/telemetry-js": "^1.6.1" + } + }, + "node_modules/@ibm/plex-sans-devanagari": { + "version": "1.1.0", + "hasInstallScript": true, + "license": "OFL-1.1", + "dependencies": { + "@ibm/telemetry-js": "^1.6.1" + } + }, + "node_modules/@ibm/plex-sans-hebrew": { + "version": "1.1.0", + "hasInstallScript": true, + "license": "OFL-1.1", + "dependencies": { + "@ibm/telemetry-js": "^1.6.1" + } + }, + "node_modules/@ibm/plex-sans-thai": { + "version": "1.1.0", + "hasInstallScript": true, + "license": "OFL-1.1", + "dependencies": { + "@ibm/telemetry-js": "^1.6.1" + } + }, + "node_modules/@ibm/plex-sans-thai-looped": { + "version": "1.1.0", + "hasInstallScript": true, + "license": "OFL-1.1", + "dependencies": { + "@ibm/telemetry-js": "^1.6.1" + } + }, + "node_modules/@ibm/plex-serif": { + "version": "1.1.0", + "hasInstallScript": true, + "license": "OFL-1.1", + "dependencies": { + "@ibm/telemetry-js": "^1.6.1" + } + }, + "node_modules/@ibm/telemetry-js": { + "version": "1.11.0", + "license": "Apache-2.0", + "bin": { + "ibmtelemetry": "dist/collect.js" + } + }, + "node_modules/@internationalized/number": { + "version": "3.6.5", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/string-width/node_modules/emoji-regex": { + "version": "9.2.2", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "license": "MIT" + }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.0", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@swc/helpers": { + "version": "0.5.18", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.27", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@wailsio/runtime": { + "version": "3.0.0-alpha.79", + "license": "MIT" + }, + "node_modules/abbrev": { + "version": "2.0.0", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001766", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chokidar": { + "version": "4.0.3", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/classnames": { + "version": "2.5.1", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "6.0.0", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/color": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/commander": { + "version": "10.0.1", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.1", + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "license": "MIT", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "node_modules/cronstrue": { + "version": "3.9.0", + "license": "MIT", + "bin": { + "cronstrue": "bin/cli.js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "8.0.3", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/discontinuous-range": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/downshift": { + "version": "9.0.10", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.5", + "compute-scroll-into-view": "^3.1.0", + "prop-types": "^15.8.1", + "react-is": "18.2.0", + "tslib": "^2.6.2" + }, + "peerDependencies": { + "react": ">=16.12.0" + } + }, + "node_modules/downshift/node_modules/react-is": { + "version": "18.2.0", + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "license": "MIT" + }, + "node_modules/editorconfig": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/semver": { + "version": "7.7.3", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.279", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "license": "MIT" + }, + "node_modules/es-toolkit": { + "version": "1.44.0", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/esbuild": { + "version": "0.21.5", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flatpickr": { + "version": "4.6.13", + "license": "MIT" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/immutable": { + "version": "5.1.4", + "license": "MIT" + }, + "node_modules/ini": { + "version": "1.3.8", + "license": "ISC" + }, + "node_modules/invariant": { + "version": "2.2.4", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "license": "MIT", + "optional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-beautify": { + "version": "1.15.4", + "license": "MIT", + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.4", + "glob": "^10.4.2", + "js-cookie": "^3.0.5", + "nopt": "^7.2.1" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/marked": { + "version": "17.0.1", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/minimatch": { + "version": "9.0.1", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/moo": { + "version": "0.5.2", + "license": "BSD-3-Clause" + }, + "node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nearley": { + "version": "2.20.1", + "license": "MIT", + "dependencies": { + "commander": "^2.19.0", + "moo": "^0.5.0", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6" + }, + "bin": { + "nearley-railroad": "bin/nearley-railroad.js", + "nearley-test": "bin/nearley-test.js", + "nearley-unparse": "bin/nearley-unparse.js", + "nearleyc": "bin/nearleyc.js" + }, + "funding": { + "type": "individual", + "url": "https://nearley.js.org/#give-to-nearley" + } + }, + "node_modules/nearley/node_modules/commander": { + "version": "2.20.3", + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "license": "MIT", + "optional": true + }, + "node_modules/node-releases": { + "version": "2.0.27", + "dev": true, + "license": "MIT" + }, + "node_modules/nopt": { + "version": "7.2.1", + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "license": "BlueOak-1.0.0" + }, + "node_modules/papaparse": { + "version": "5.5.3", + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "license": "ISC" + }, + "node_modules/php-serialize": { + "version": "5.1.3", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pngjs": { + "version": "5.0.0", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "license": "ISC" + }, + "node_modules/qrcode": { + "version": "1.5.4", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/railroad-diagrams": { + "version": "1.0.0", + "license": "CC0-1.0" + }, + "node_modules/randexp": { + "version": "0.4.6", + "license": "MIT", + "dependencies": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/react": { + "version": "18.3.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "license": "MIT" + }, + "node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/ret": { + "version": "0.1.15", + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/rollup": { + "version": "4.57.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.0", + "@rollup/rollup-android-arm64": "4.57.0", + "@rollup/rollup-darwin-arm64": "4.57.0", + "@rollup/rollup-darwin-x64": "4.57.0", + "@rollup/rollup-freebsd-arm64": "4.57.0", + "@rollup/rollup-freebsd-x64": "4.57.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.0", + "@rollup/rollup-linux-arm-musleabihf": "4.57.0", + "@rollup/rollup-linux-arm64-gnu": "4.57.0", + "@rollup/rollup-linux-arm64-musl": "4.57.0", + "@rollup/rollup-linux-loong64-gnu": "4.57.0", + "@rollup/rollup-linux-loong64-musl": "4.57.0", + "@rollup/rollup-linux-ppc64-gnu": "4.57.0", + "@rollup/rollup-linux-ppc64-musl": "4.57.0", + "@rollup/rollup-linux-riscv64-gnu": "4.57.0", + "@rollup/rollup-linux-riscv64-musl": "4.57.0", + "@rollup/rollup-linux-s390x-gnu": "4.57.0", + "@rollup/rollup-linux-x64-gnu": "4.57.0", + "@rollup/rollup-linux-x64-musl": "4.57.0", + "@rollup/rollup-openbsd-x64": "4.57.0", + "@rollup/rollup-openharmony-arm64": "4.57.0", + "@rollup/rollup-win32-arm64-msvc": "4.57.0", + "@rollup/rollup-win32-ia32-msvc": "4.57.0", + "@rollup/rollup-win32-x64-gnu": "4.57.0", + "@rollup/rollup-win32-x64-msvc": "4.57.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/sass": { + "version": "1.97.3", + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sql-formatter": { + "version": "15.7.0", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "nearley": "^2.20.1" + }, + "bin": { + "sql-formatter": "bin/sql-formatter-cli.cjs" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tabbable": { + "version": "6.4.0", + "license": "MIT" + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "license": "0BSD" + }, + "node_modules/ulid": { + "version": "3.0.2", + "license": "MIT", + "bin": { + "ulid": "dist/cli.js" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "license": "ISC" + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/xml-formatter": { + "version": "3.6.7", + "license": "MIT", + "dependencies": { + "xml-parser-xo": "^4.1.5" + }, + "engines": { + "node": ">= 16" + } + }, + "node_modules/xml-parser-xo": { + "version": "4.1.5", + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "license": "ISC" + }, + "node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "15.4.1", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json index 6c8e795..d701f84 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,12 +7,14 @@ "dev": "vite", "build:dev": "vite build --minify false --mode development", "build": "vite build --mode production", - "preview": "vite preview" + "preview": "vite preview", + "format": "prettier --write .", + "format:check": "prettier --check ." }, "dependencies": { - "@carbon/icons-react": "^11.71.0", - "@carbon/react": "^1.97.0", - "@carbon/styles": "^1.96.0", + "@carbon/icons-react": "^11.76.0", + "@carbon/react": "^1.102.0", + "@carbon/styles": "^1.101.0", "@wailsio/runtime": "^3.0.0-alpha.79", "cronstrue": "^3.9.0", "diff": "^8.0.2", @@ -34,6 +36,7 @@ "@types/react": "^18.0.17", "@types/react-dom": "^18.0.6", "@vitejs/plugin-react": "^4.0.0", + "prettier": "^3.5.3", "vite": "^5.4.21" } -} \ No newline at end of file +} diff --git a/frontend/src/App.css b/frontend/src/App.css index 4c0593d..074e77f 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,179 +1,181 @@ /* ... existing styles ... */ .app-container { - display: flex; - flex-direction: column; - width: 100vw; - height: 100vh; - overflow: hidden; + display: flex; + flex-direction: column; + width: 100vw; + height: 100vh; + overflow: hidden; } .app-body { - display: flex; - flex: 1; - overflow: hidden; + display: flex; + flex: 1; + overflow: hidden; } .main-content { - flex: 1; - height: 100%; - overflow: auto; - position: relative; - background-color: var(--bg-color); - transition: margin-left 0.3s ease; + flex: 1; + height: 100%; + overflow: auto; + position: relative; + background-color: var(--bg-color); + transition: margin-left 0.3s ease; } .content-area { - flex: 1; - overflow-y: auto; - padding: 24px; + flex: 1; + overflow-y: auto; + padding: 24px; } /* Sidebar Styles */ .sidebar { - width: 260px; - background-color: var(--sidebar-bg); - border-right: 1px solid var(--border-color); - display: flex; - flex-direction: column; - transition: margin-left 0.3s ease, width 0.3s ease, opacity 0.3s ease; - overflow: hidden; - flex-shrink: 0; - height: 100%; + width: 260px; + background-color: var(--sidebar-bg); + border-right: 1px solid var(--border-color); + display: flex; + flex-direction: column; + transition: + margin-left 0.3s ease, + width 0.3s ease, + opacity 0.3s ease; + overflow: hidden; + flex-shrink: 0; + height: 100%; } .sidebar.hidden { - margin-left: -260px; - opacity: 0; + margin-left: -260px; + opacity: 0; } .nav-scroll-area { - flex: 1; - overflow-y: auto; - padding: 12px 8px; + flex: 1; + overflow-y: auto; + padding: 12px 8px; } .nav-list { - list-style: none; - padding: 0; - margin: 0; + list-style: none; + padding: 0; + margin: 0; } .nav-item { - margin-bottom: 2px; + margin-bottom: 2px; } .nav-button { - width: 100%; - text-align: left; - padding: 8px 12px; - background: transparent; - color: var(--text-secondary); - border-radius: 6px; - font-size: 0.9rem; - display: flex; - align-items: center; - justify-content: space-between; - /* Changed for pin icon */ - gap: 10px; - white-space: nowrap; - transition: all 0.2s; - border: 1px solid transparent; - position: relative; + width: 100%; + text-align: left; + padding: 8px 12px; + background: transparent; + color: var(--text-secondary); + border-radius: 6px; + font-size: 0.9rem; + display: flex; + align-items: center; + justify-content: space-between; + /* Changed for pin icon */ + gap: 10px; + white-space: nowrap; + transition: all 0.2s; + border: 1px solid transparent; + position: relative; } .nav-button:hover { - background-color: rgba(255, 255, 255, 0.05); - color: var(--text-primary); + background-color: rgba(255, 255, 255, 0.05); + color: var(--text-primary); } .nav-button.active { - background-color: rgba(88, 166, 255, 0.15); - color: var(--accent-color); - border-color: rgba(88, 166, 255, 0.2); - font-weight: 500; + background-color: rgba(88, 166, 255, 0.15); + color: var(--accent-color); + border-color: rgba(88, 166, 255, 0.2); + font-weight: 500; } .nav-content { - display: flex; - align-items: center; - gap: 12px; - overflow: hidden; + display: flex; + align-items: center; + gap: 12px; + overflow: hidden; } .nav-icon { - width: 20px; - display: inline-block; - text-align: center; - flex-shrink: 0; + width: 20px; + display: inline-block; + text-align: center; + flex-shrink: 0; } .nav-text { - overflow: hidden; - text-overflow: ellipsis; + overflow: hidden; + text-overflow: ellipsis; } .nav-action { - opacity: 0; - transition: opacity 0.2s; - font-size: 0.8rem; - padding: 2px 6px; - border-radius: 4px; - color: var(--text-secondary); + opacity: 0; + transition: opacity 0.2s; + font-size: 0.8rem; + padding: 2px 6px; + border-radius: 4px; + color: var(--text-secondary); } .nav-button:hover .nav-action { - opacity: 1; + opacity: 1; } .nav-action:hover { - background-color: rgba(255, 255, 255, 0.1); - color: var(--text-primary); + background-color: rgba(255, 255, 255, 0.1); + color: var(--text-primary); } /* Section Headers & Separators */ .sidebar-section-header { - padding: 10px 12px 6px; - font-size: 0.75rem; - text-transform: uppercase; - color: var(--text-secondary); - font-weight: 600; - letter-spacing: 0.5px; - display: flex; - align-items: center; - gap: 8px; + padding: 10px 12px 6px; + font-size: 0.75rem; + text-transform: uppercase; + color: var(--text-secondary); + font-weight: 600; + letter-spacing: 0.5px; + display: flex; + align-items: center; + gap: 8px; } .sidebar-separator { - height: 1px; - background-color: var(--border-color); - margin: 8px 12px; - opacity: 0.5; + height: 1px; + background-color: var(--border-color); + margin: 8px 12px; + opacity: 0.5; } - /* Toggle Button */ .sidebar-toggle { - position: absolute; - top: 15px; - left: 15px; - z-index: 100; - background-color: var(--surface-color); - border: 1px solid var(--border-color); - color: var(--text-secondary); - width: 32px; - height: 32px; - border-radius: 6px; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - transition: all 0.2s; + position: absolute; + top: 15px; + left: 15px; + z-index: 100; + background-color: var(--surface-color); + border: 1px solid var(--border-color); + color: var(--text-secondary); + width: 32px; + height: 32px; + border-radius: 6px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.2s; } .sidebar-toggle:hover { - border-color: var(--text-secondary); - color: var(--text-primary); + border-color: var(--text-secondary); + color: var(--text-primary); } /* Title Bar Styles */ @@ -272,114 +274,114 @@ /* Tool Container and Panes (Same as before) */ .tool-container { - max-width: 1400px; - margin: 0 auto; - width: 100%; - height: 100%; - display: flex; - flex-direction: column; + max-width: 1400px; + margin: 0 auto; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; } .tool-header { - padding-bottom: 10px; - border-bottom: 1px solid var(--surface-color); + padding-bottom: 10px; + border-bottom: 1px solid var(--surface-color); } .tool-title { - font-size: 1.5rem; - font-weight: 600; - margin-bottom: 4px; + font-size: 1.5rem; + font-weight: 600; + margin-bottom: 4px; } .tool-desc { - color: var(--text-secondary); - font-size: 0.9rem; + color: var(--text-secondary); + font-size: 0.9rem; } .split-pane { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 16px; - flex: 1; - min-height: 0; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16px; + flex: 1; + min-height: 0; } .pane { - display: flex; - flex-direction: column; - gap: 8px; - height: 100%; - min-height: 0; + display: flex; + flex-direction: column; + gap: 8px; + height: 100%; + min-height: 0; } .pane-header { - display: flex; - justify-content: space-between; - align-items: center; - min-height: 28px; + display: flex; + justify-content: space-between; + align-items: center; + min-height: 28px; } .pane-label { - font-weight: 600; - font-size: 0.85rem; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.5px; + font-weight: 600; + font-size: 0.85rem; + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.5px; } .code-editor { - flex: 1; - background-color: var(--sidebar-bg); - border: 1px solid var(--border-color); - border-radius: 6px; - color: var(--text-primary); - font-family: 'JetBrains Mono', 'Menlo', 'Monaco', monospace; - padding: 12px; - resize: none; - line-height: 1.5; - font-size: 13px; - white-space: pre; - overflow: auto; + flex: 1; + background-color: var(--sidebar-bg); + border: 1px solid var(--border-color); + border-radius: 6px; + color: var(--text-primary); + font-family: 'JetBrains Mono', 'Menlo', 'Monaco', monospace; + padding: 12px; + resize: none; + line-height: 1.5; + font-size: 13px; + white-space: pre; + overflow: auto; } .code-editor:focus { - outline: none; - border-color: var(--accent-color); + outline: none; + border-color: var(--accent-color); } .controls { - padding: 12px 16px; - background-color: var(--surface-color); - border-radius: 8px; - border: 1px solid var(--border-color); - margin-bottom: 16px; - display: flex; - align-items: center; - gap: 12px; - flex-wrap: wrap; + padding: 12px 16px; + background-color: var(--surface-color); + border-radius: 8px; + border: 1px solid var(--border-color); + margin-bottom: 16px; + display: flex; + align-items: center; + gap: 12px; + flex-wrap: wrap; } .btn-primary { - background-color: var(--accent-color); - color: white; - padding: 6px 16px; - font-weight: 600; - font-size: 0.9rem; + background-color: var(--accent-color); + color: white; + padding: 6px 16px; + font-weight: 600; + font-size: 0.9rem; } .btn-primary:hover { - background-color: var(--accent-hover); + background-color: var(--accent-hover); } .btn-secondary { - background-color: transparent; - border: 1px solid var(--border-color); - color: var(--text-primary); - padding: 6px 12px; - font-size: 0.9rem; + background-color: transparent; + border: 1px solid var(--border-color); + color: var(--text-primary); + padding: 6px 12px; + font-size: 0.9rem; } .btn-secondary:hover { - border-color: var(--text-secondary); - background-color: rgba(255, 255, 255, 0.03); -} \ No newline at end of file + border-color: var(--text-secondary); + background-color: rgba(255, 255, 255, 0.03); +} diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 6727ac5..e7eafa1 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -20,129 +20,146 @@ import ColorConverter from './pages/ColorConverter'; // Error boundary for catching React rendering errors class ErrorBoundary extends React.Component { - constructor(props) { - super(props); - this.state = { hasError: false, error: null, errorInfo: null }; + constructor(props) { + super(props); + this.state = { hasError: false, error: null, errorInfo: null }; + } + + static getDerivedStateFromError(error) { + return { hasError: true }; + } + + componentDidCatch(error, errorInfo) { + console.error('ErrorBoundary caught an error:', error, errorInfo); + this.setState({ + error: error, + errorInfo: errorInfo, + }); + } + + render() { + if (this.state.hasError) { + return ( +
+

Something went wrong

+

The application encountered an error. Please try refreshing the page.

+
+ Error details + {this.state.error && this.state.error.toString()} +
+ {this.state.errorInfo && this.state.errorInfo.componentStack} +
+
+ ); } - static getDerivedStateFromError(error) { - return { hasError: true }; - } - - componentDidCatch(error, errorInfo) { - console.error('ErrorBoundary caught an error:', error, errorInfo); - this.setState({ - error: error, - errorInfo: errorInfo - }); - } - - render() { - if (this.state.hasError) { - return ( -
-

Something went wrong

-

The application encountered an error. Please try refreshing the page.

-
- Error details - {this.state.error && this.state.error.toString()} -
- {this.state.errorInfo && this.state.errorInfo.componentStack} -
-
- ); - } - - return this.props.children; - } + return this.props.children; + } } function App() { - console.log('App mounting'); - const [activeTool, setActiveTool] = useState('text-converter'); - const [isSidebarOpen, setIsSidebarOpen] = useState(true); - const [theme, setTheme] = useState('g100'); // 'white', 'g10', 'g90', 'g100' - const [themeMode, setThemeMode] = useState('dark'); // 'system', 'light', 'dark' - - const toggleSidebar = () => setIsSidebarOpen(!isSidebarOpen); - - useEffect(() => { - // Detect System Theme - const matchMedia = window.matchMedia('(prefers-color-scheme: dark)'); - - const updateTheme = () => { - if (themeMode === 'system') { - setTheme(matchMedia.matches ? 'g100' : 'white'); - } else if (themeMode === 'dark') { - setTheme('g100'); - } else { - setTheme('white'); - } - }; - - updateTheme(); - matchMedia.addEventListener('change', updateTheme); - return () => matchMedia.removeEventListener('change', updateTheme); - }, [themeMode]); - - useEffect(() => { - const handleKeyDown = (e) => { - if ((e.metaKey || e.ctrlKey) && e.key === 'b') { - e.preventDefault(); - toggleSidebar(); - } - }; - - window.addEventListener('keydown', handleKeyDown); - return () => window.removeEventListener('keydown', handleKeyDown); - }, [isSidebarOpen]); - - const renderTool = () => { - switch (activeTool) { - case 'text-converter': return ; - case 'string-utilities': return ; - case 'datetime-converter': return ; - case 'jwt': return ; - case 'barcode': return ; - case 'data-generator': return ; - case 'code-formatter': return ; - case 'color-converter': return ; - case 'regexp': return ; - case 'cron': return ; - case 'diff': return ; - case 'number-converter': return ; - default: return
Select a tool
; - } + console.log('App mounting'); + const [activeTool, setActiveTool] = useState('text-converter'); + const [isSidebarOpen, setIsSidebarOpen] = useState(true); + const [theme, setTheme] = useState('g100'); // 'white', 'g10', 'g90', 'g100' + const [themeMode, setThemeMode] = useState('dark'); // 'system', 'light', 'dark' + + const toggleSidebar = () => setIsSidebarOpen(!isSidebarOpen); + + useEffect(() => { + // Detect System Theme + const matchMedia = window.matchMedia('(prefers-color-scheme: dark)'); + + const updateTheme = () => { + if (themeMode === 'system') { + setTheme(matchMedia.matches ? 'g100' : 'white'); + } else if (themeMode === 'dark') { + setTheme('g100'); + } else { + setTheme('white'); + } + }; + + updateTheme(); + matchMedia.addEventListener('change', updateTheme); + return () => matchMedia.removeEventListener('change', updateTheme); + }, [themeMode]); + + useEffect(() => { + const handleKeyDown = (e) => { + if ((e.metaKey || e.ctrlKey) && e.key === 'b') { + e.preventDefault(); + toggleSidebar(); + } }; - return ( - - -
- - -
- - -
-
- {renderTool()} -
-
-
-
-
-
- ); + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [isSidebarOpen]); + + const renderTool = () => { + switch (activeTool) { + case 'text-converter': + return ; + case 'string-utilities': + return ; + case 'datetime-converter': + return ; + case 'jwt': + return ; + case 'barcode': + return ; + case 'data-generator': + return ; + case 'code-formatter': + return ; + case 'color-converter': + return ; + case 'regexp': + return ; + case 'cron': + return ; + case 'diff': + return ; + case 'number-converter': + return ; + default: + return
Select a tool
; + } + }; + + return ( + + +
+ + +
+ + +
+
{renderTool()}
+
+
+
+
+
+ ); } export default App; diff --git a/frontend/src/components/AnalogClockWidget.jsx b/frontend/src/components/AnalogClockWidget.jsx index ed25b69..bf5b10f 100644 --- a/frontend/src/components/AnalogClockWidget.jsx +++ b/frontend/src/components/AnalogClockWidget.jsx @@ -29,7 +29,7 @@ export default function AnalogClockWidget({ date }) { const y1 = center + (radius - 15) * Math.sin(angle); const x2 = center + (radius - 5) * Math.cos(angle); const y2 = center + (radius - 5) * Math.sin(angle); - + hourMarkers.push( +
{/* Clock face */} {/* Center dot */} - + {/* Digital display */} -
-
+
+
{displayHours}:{displayMinutes}:{displaySeconds}
-
+
{ampm}
diff --git a/frontend/src/components/CalendarWidget.jsx b/frontend/src/components/CalendarWidget.jsx index 5432e00..db28686 100644 --- a/frontend/src/components/CalendarWidget.jsx +++ b/frontend/src/components/CalendarWidget.jsx @@ -19,8 +19,18 @@ export default function CalendarWidget({ date, onDateSelect }) { // Month names const monthNames = [ - 'January', 'February', 'March', 'April', 'May', 'June', - 'July', 'August', 'September', 'October', 'November', 'December' + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', ]; // Day names @@ -28,7 +38,7 @@ export default function CalendarWidget({ date, onDateSelect }) { // Generate calendar days const days = []; - + // Previous month days for (let i = firstDay - 1; i >= 0; i--) { days.push({ @@ -38,15 +48,14 @@ export default function CalendarWidget({ date, onDateSelect }) { isSelected: false, }); } - + // Current month days const today = new Date(); for (let i = 1; i <= daysInMonth; i++) { - const isToday = i === today.getDate() && - month === today.getMonth() && - year === today.getFullYear(); + const isToday = + i === today.getDate() && month === today.getMonth() && year === today.getFullYear(); const isSelected = i === day; - + days.push({ day: i, currentMonth: true, @@ -54,7 +63,7 @@ export default function CalendarWidget({ date, onDateSelect }) { isSelected, }); } - + // Next month days to fill the grid const remainingCells = 42 - days.length; // 6 rows * 7 columns for (let i = 1; i <= remainingCells; i++) { @@ -68,7 +77,7 @@ export default function CalendarWidget({ date, onDateSelect }) { const handleDayClick = (dayInfo, index) => { if (!dayInfo.currentMonth || !onDateSelect) return; - + // Calculate the actual date const clickedDate = new Date(year, month, dayInfo.day); onDateSelect(clickedDate); @@ -89,19 +98,23 @@ export default function CalendarWidget({ date, onDateSelect }) { }; return ( -
+
{/* Header */} -
+
- -
+ +
{monthNames[month]} {year}
- + - - ))} - - {regularTools.length > 0 &&
} - - )} +
+ {pinnedTools.length > 0 && ( + <> +
+ 📌 + Pinned +
+
    + {pinnedTools.map((tool) => ( +
  • + +
  • + ))} +
+ {regularTools.length > 0 &&
} + + )} -
    - {regularTools.map(tool => ( -
  • - -
  • - ))} -
+
    + {regularTools.map((tool) => ( +
  • + +
  • + ))} +
- {regularTools.length === 0 && pinnedTools.length === 0 && ( -
- No tools found -
- )} -
-
- ); + {regularTools.length === 0 && pinnedTools.length === 0 && ( +
+ No tools found +
+ )} +
+
+ ); } export default Sidebar; diff --git a/frontend/src/components/TitleBar.jsx b/frontend/src/components/TitleBar.jsx index c7cd89e..3af320b 100644 --- a/frontend/src/components/TitleBar.jsx +++ b/frontend/src/components/TitleBar.jsx @@ -2,19 +2,20 @@ import React from 'react'; import { IconButton, OverflowMenu, OverflowMenuItem } from '@carbon/react'; import { Menu, Close, Subtract, Maximize, Settings } from '@carbon/icons-react'; -export function TitleBar({ - isSidebarOpen, - toggleSidebar, +export function TitleBar({ + isSidebarOpen, + toggleSidebar, appName = 'DevToolbox', themeMode, - setThemeMode + setThemeMode, }) { // Detect if running in desktop mode const isDesktop = typeof window !== 'undefined' && window.wails; - + // Detect platform const userAgent = navigator.userAgent.toLowerCase(); - const isMac = userAgent.includes('mac') && !userAgent.includes('iphone') && !userAgent.includes('ipad'); + const isMac = + userAgent.includes('mac') && !userAgent.includes('iphone') && !userAgent.includes('ipad'); // Don't render in browser mode if (!isDesktop) { @@ -73,9 +74,21 @@ export function TitleBar({ title="Theme Settings" className="titlebar-settings" > - setThemeMode('system')} requireTitle /> - setThemeMode('dark')} requireTitle /> - setThemeMode('light')} requireTitle /> + setThemeMode('system')} + requireTitle + /> + setThemeMode('dark')} + requireTitle + /> + setThemeMode('light')} + requireTitle + /> {/* Window controls for non-macOS platforms */} diff --git a/frontend/src/components/ToolUI.jsx b/frontend/src/components/ToolUI.jsx index 60c39e7..3e79202 100644 --- a/frontend/src/components/ToolUI.jsx +++ b/frontend/src/components/ToolUI.jsx @@ -8,109 +8,123 @@ export { LAYOUT_DIRECTIONS, TOGGLE_POSITIONS } from './layout/constants'; export { ToolCopyButton, ToolTextArea, ToolInput, ToolInputGroup, ToolTabBar } from './inputs'; export function ToolHeader({ title, description }) { - return ( -
-

{title}

-

{description}

-
- ); + return ( +
+

{title}

+

{description}

+
+ ); } export function ToolControls({ children, style = {} }) { - return ( -
- {children} -
- ); + return ( +
+ {children} +
+ ); } export function ToolPane({ label, value, onChange, readOnly, placeholder, onCopy, ...props }) { - const handleCopy = () => { - if (onCopy) { - onCopy(); - } else if (value) { - navigator.clipboard.writeText(value); - } - }; + const handleCopy = () => { + if (onCopy) { + onCopy(); + } else if (value) { + navigator.clipboard.writeText(value); + } + }; - return ( -
+
+ +
+
+