diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7bfcdd5..0385077 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,10 @@ on: - master release: types: - - created + - released + pull_request: + branches: + - master jobs: build: diff --git a/README.md b/README.md index 0d6c16c..7d20aee 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # JetTreeMark for VS Code ![Build](https://github.com/HichemTab-tech/JetTreeMark-vscode/actions/workflows/ci.yml/badge.svg) -[![Version](https://img.shields.io/badge/version-1.0.1-blue.svg)](https://github.com/HichemTab-tech/JetTreeMark-vscode/releases) [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/HichemTab-tech/JetTreeMark-vscode/blob/master/LICENSE) +[![Version](https://img.shields.io/badge/version-1.1.0-blue.svg)](https://github.com/HichemTab-tech/JetTreeMark-vscode/releases) [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/HichemTab-tech/JetTreeMark-vscode/blob/master/LICENSE) --- @@ -10,7 +10,7 @@ **JetTreeMark** for VS Code brings the same lightning-fast, one-click tree-view generation you know from the IntelliJ plugin into your favorite editor. Right-click any folder in the Explorer, choose **Show Tree View**, -and you’ll instantly get a clean, customizable markdown-compatible tree of your project—ready to copy, share, +and you'll instantly get a clean, customizable markdown-compatible tree of your project—ready to copy, share, or document. 😉 @@ -24,6 +24,7 @@ or document. - 📂 **Generate** a neat tree view of any selected folder - 📋 **Copy** the filtered structure to clipboard with one click - ✔️ **Tri-state checkboxes** let you include/exclude subfolders & files +- 🖱️ **Context menu** with powerful selection operations (check/uncheck folders, files, levels) - ⚡ **Lightweight**—built as a native VS Code Webview extension - 🎨 **Tailwind-powered** UI for a clean, responsive look @@ -48,7 +49,7 @@ or document. ### From the Marketplace JetTreeMark is now available on the Visual Studio Marketplace! -Install it directly from VS Code’s Extensions view—just search for **JetTreeMark** and click **Install**. +Install it directly from VS Code's Extensions view—just search for **JetTreeMark** and click **Install**. ### Manual Installation @@ -93,7 +94,7 @@ vsce package ## 🎯 How to Use 1. **Right-click** on any folder in the Explorer. -2. Select **“Show Tree View”** from the context menu. +2. Select **"Show Tree View"** from the context menu. ![How to use the JetTreeMark plugin from folder context menu](https://github.com/HichemTab-tech/JetTreeMark-vscode/blob/master/meta/screenshot-1.png "Screenshot -JetTreeMark in context menu-") @@ -102,7 +103,15 @@ vsce package ![How to use the JetTreeMark plugin to exclude nodes from the tree view result](https://github.com/HichemTab-tech/JetTreeMark-vscode/blob/master/meta/screenshot-2.png "Screenshot - filter nodes from tree results -") -5. Click **“Copy Selected Structure”** at the top to copy your markdown tree. +5. **Right-click** on any node to access the context menu with powerful selection operations: + - **Check All Children** - Include all files and folders under this node + - **Check All Folders** - Include only folders under this node + - **Uncheck All Children** - Exclude all files and folders under this node + - **Check Without Children** - Include only this node, not its children + - **Level-Specific Operations** - Apply operations only to the current level + - **Expand/Collapse** - Control node visibility + +6. Click **"Copy Selected Structure"** at the top to copy your markdown tree. --- diff --git a/package.json b/package.json index 3bcf3c9..477f450 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "jettreemark", "displayName": "JetTreeMark", "description": "JetTreeMark is a VS Code plugin that generates a markdown-compatible structure tree for selected files and folders", - "version": "1.0.1", + "version": "1.1.0", "publisher": "HichemTab-tech", "homepage": "https://github.com/HichemTab-tech/JetTreeMark-vscode", "repository": { @@ -81,6 +81,7 @@ "@vscode/test-cli": "^0.0.10", "@vscode/test-electron": "^2.4.1", "@vscode/vsce": "^3.3.2", + "cross-env": "^7.0.3", "eslint": "^9.23.0", "ts-loader": "^9.5.2", "typescript": "^5.8.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c3395ab..0ae233c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ importers: '@vscode/vsce': specifier: ^3.3.2 version: 3.3.2 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 eslint: specifier: ^9.23.0 version: 9.25.1(jiti@2.4.2) @@ -646,6 +649,11 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2684,6 +2692,10 @@ snapshots: core-util-is@1.0.3: {} + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.6 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 0a3beb3..44ec94b 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -5,6 +5,16 @@ import * as path from 'path'; import { buildTreeNode } from '../extension'; import * as fs from 'fs'; import * as os from "os"; +// Import tree-utils functions for testing context menu options +import { + checkAllChildren, + checkAllFolders, + uncheckAllChildren, + checkWithoutChildren, + checkOnlyFoldersAtLevel, + checkOnlyFilesAtLevel, + checkAllChildrenAtLevel +} from './tree-utils'; suite('JetTreeMark-vscode Test Suite', () => { test('Extension is present in the registry', () => { @@ -63,4 +73,150 @@ suite('JetTreeMark-vscode Test Suite', () => { assert.ok(bNode && bNode.type === 'file', 'b.txt should exist in subdir'); }); }); -}); \ No newline at end of file + // Test suite for context menu options + suite('Context Menu Options Tests', () => { + // Sample tree structure for testing + let sampleTree: any[]; + + setup(() => { + // Create a sample tree structure before each test + sampleTree = [ + { + id: 'root', + name: 'root', + type: 'folder', + checked: false, + indeterminate: false, + children: [ + { + id: 'folder1', + name: 'folder1', + type: 'folder', + checked: false, + indeterminate: false, + children: [ + { + id: 'file1', + name: 'file1.txt', + type: 'file', + checked: false + }, + { + id: 'file2', + name: 'file2.txt', + type: 'file', + checked: false + } + ] + }, + { + id: 'folder2', + name: 'folder2', + type: 'folder', + checked: false, + indeterminate: false, + children: [ + { + id: 'file3', + name: 'file3.txt', + type: 'file', + checked: false + } + ] + }, + { + id: 'file4', + name: 'file4.txt', + type: 'file', + checked: false + } + ] + } + ]; + }); + + test('checkAllChildren sets all nodes to checked', () => { + const result = checkAllChildren(sampleTree); + + // Check that all nodes are checked + assert.strictEqual(result[0].checked, true, 'Root node should be checked'); + assert.strictEqual(result[0].children![0].checked, true, 'folder1 should be checked'); + assert.strictEqual(result[0].children![0].children![0].checked, true, 'file1 should be checked'); + assert.strictEqual(result[0].children![0].children![1].checked, true, 'file2 should be checked'); + assert.strictEqual(result[0].children![1].checked, true, 'folder2 should be checked'); + assert.strictEqual(result[0].children![1].children![0].checked, true, 'file3 should be checked'); + assert.strictEqual(result[0].children![2].checked, true, 'file4 should be checked'); + }); + + test('checkAllFolders sets only folder nodes to checked', () => { + const result = checkAllFolders(sampleTree); + + // Check that only folder nodes are checked + assert.strictEqual(result[0].checked, true, 'Root node should be checked'); + assert.strictEqual(result[0].children![0].checked, true, 'folder1 should be checked'); + assert.strictEqual(result[0].children![0].children![0].checked, false, 'file1 should not be checked'); + assert.strictEqual(result[0].children![0].children![1].checked, false, 'file2 should not be checked'); + assert.strictEqual(result[0].children![1].checked, true, 'folder2 should be checked'); + assert.strictEqual(result[0].children![1].children![0].checked, false, 'file3 should not be checked'); + assert.strictEqual(result[0].children![2].checked, false, 'file4 should not be checked'); + }); + + test('uncheckAllChildren sets all nodes to unchecked', () => { + // First check all nodes + sampleTree = checkAllChildren(sampleTree); + + // Then uncheck all nodes + const result = uncheckAllChildren(sampleTree); + + // Check that all nodes are unchecked + assert.strictEqual(result[0].checked, false, 'Root node should be unchecked'); + assert.strictEqual(result[0].children![0].checked, false, 'folder1 should be unchecked'); + assert.strictEqual(result[0].children![0].children![0].checked, false, 'file1 should be unchecked'); + assert.strictEqual(result[0].children![0].children![1].checked, false, 'file2 should be unchecked'); + assert.strictEqual(result[0].children![1].checked, false, 'folder2 should be unchecked'); + assert.strictEqual(result[0].children![1].children![0].checked, false, 'file3 should be unchecked'); + assert.strictEqual(result[0].children![2].checked, false, 'file4 should be unchecked'); + }); + + test('checkWithoutChildren checks a node without affecting its children', () => { + // Apply checkWithoutChildren to folder1 + const folder1 = sampleTree[0].children![0]; + const result = checkWithoutChildren(folder1); + + // Check that folder1 is checked but its children are not + assert.strictEqual(result.checked, true, 'folder1 should be checked'); + assert.strictEqual(result.children![0].checked, false, 'file1 should not be checked'); + assert.strictEqual(result.children![1].checked, false, 'file2 should not be checked'); + }); + + test('checkOnlyFoldersAtLevel checks only folder nodes at a specific level', () => { + // Apply checkOnlyFoldersAtLevel to root's children + const result = checkOnlyFoldersAtLevel(sampleTree[0].children!); + + // Check that only folder nodes at this level are checked + assert.strictEqual(result[0].checked, true, 'folder1 should be checked'); + assert.strictEqual(result[1].checked, true, 'folder2 should be checked'); + assert.strictEqual(result[2].checked, false, 'file4 should not be checked'); + }); + + test('checkOnlyFilesAtLevel checks only file nodes at a specific level', () => { + // Apply checkOnlyFilesAtLevel to root's children + const result = checkOnlyFilesAtLevel(sampleTree[0].children!); + + // Check that only file nodes at this level are checked + assert.strictEqual(result[0].checked, false, 'folder1 should not be checked'); + assert.strictEqual(result[1].checked, false, 'folder2 should not be checked'); + assert.strictEqual(result[2].checked, true, 'file4 should be checked'); + }); + + test('checkAllChildrenAtLevel checks all nodes at a specific level', () => { + // Apply checkAllChildrenAtLevel to root's children + const result = checkAllChildrenAtLevel(sampleTree[0].children!); + + // Check that all nodes at this level are checked + assert.strictEqual(result[0].checked, true, 'folder1 should be checked'); + assert.strictEqual(result[1].checked, true, 'folder2 should be checked'); + assert.strictEqual(result[2].checked, true, 'file4 should be checked'); + }); + }); +}); diff --git a/src/test/tree-utils.ts b/src/test/tree-utils.ts new file mode 100644 index 0000000..9880968 --- /dev/null +++ b/src/test/tree-utils.ts @@ -0,0 +1,130 @@ +// Copy of the tree-utils.ts functions for testing purposes +// This file contains the same functions as webview-ui/src/lib/tree-utils.ts +// but adapted to work with the extension test environment + +export interface TreeNodeType { + id: string + name: string + type: "file" | "folder" + checked: boolean + indeterminate?: boolean + children?: TreeNodeType[] +} + +// Function to add checked property to all nodes in the tree +export function processTreeData(data: TreeNodeType[]) { + return data.map((node) => { + const newNode = { ...node, checked: true }; + if (node.children && node.children.length > 0) { + newNode.children = processTreeData(node.children); + } + return newNode; + }); +} + +// Function to filter out unchecked nodes +export function filterUncheckedNodes(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes + .filter((node) => node.checked) + .map((node) => { + const newNode = { ...node }; + if (newNode.children) { + newNode.children = filterUncheckedNodes(newNode.children); + } + delete newNode.indeterminate; + return newNode; + }); +} + +// Function to format tree as text +export function formatTreeAsText(nodes: TreeNodeType[], prefix = "", isRoot = true): string { + let result = isRoot ? "File Structure:\n\n" : ""; + + nodes.forEach((node, index) => { + const isLast = index === nodes.length - 1; + const connector = isLast ? "└──" : "├──"; + const nodeType = node.type === "folder" ? "📁" : "📄"; + + result += `${prefix}${connector} ${nodeType} ${node.name}\n`; + + if (node.children && node.children.length > 0) { + const childPrefix = prefix + (isLast ? " " : "│ "); + result += formatTreeAsText(node.children, childPrefix, false); + } + }); + + return result; +} + +// Function to check all children of a node +export function checkAllChildren(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes.map((node) => { + const newNode = { ...node, checked: true, indeterminate: false }; + if (newNode.children && newNode.children.length > 0) { + newNode.children = checkAllChildren(newNode.children); + } + return newNode; + }); +} + +// Function to check all folders in the tree +export function checkAllFolders(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes.map((node) => { + const newNode = { ...node }; + if (node.type === "folder") { + newNode.checked = true; + newNode.indeterminate = false; + } + + if (newNode.children && newNode.children.length > 0) { + newNode.children = checkAllFolders(newNode.children); + } + + return newNode; + }); +} + +// Function to uncheck all children of a node +export function uncheckAllChildren(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes.map((node) => { + const newNode = { ...node, checked: false, indeterminate: false }; + if (newNode.children && newNode.children.length > 0) { + newNode.children = uncheckAllChildren(newNode.children); + } + return newNode; + }); +} + +// Function to check a node without affecting its children +export function checkWithoutChildren(node: TreeNodeType): TreeNodeType { + return { ...node, checked: true, indeterminate: false }; +} + +// Function to check only folders at a specific level +export function checkOnlyFoldersAtLevel(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes.map((node) => { + const newNode = { ...node }; + newNode.checked = node.type === "folder"; + newNode.indeterminate = false; + + return newNode; + }); +} + +// Function to check only files at a specific level +export function checkOnlyFilesAtLevel(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes.map((node) => { + const newNode = { ...node }; + newNode.checked = node.type === "file"; + newNode.indeterminate = false; + + return newNode; + }); +} + +// Function to check all children at a specific level +export function checkAllChildrenAtLevel(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes.map((node) => { + return {...node, checked: true, indeterminate: false}; + }); +} diff --git a/webview-ui-dist/assets/index-BcEoQtVD.js b/webview-ui-dist/assets/index-BcEoQtVD.js new file mode 100644 index 0000000..3496d64 --- /dev/null +++ b/webview-ui-dist/assets/index-BcEoQtVD.js @@ -0,0 +1,161 @@ +function V0(a,i){for(var o=0;oc[s]})}}}return Object.freeze(Object.defineProperty(a,Symbol.toStringTag,{value:"Module"}))}(function(){const i=document.createElement("link").relList;if(i&&i.supports&&i.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))c(s);new MutationObserver(s=>{for(const d of s)if(d.type==="childList")for(const m of d.addedNodes)m.tagName==="LINK"&&m.rel==="modulepreload"&&c(m)}).observe(document,{childList:!0,subtree:!0});function o(s){const d={};return s.integrity&&(d.integrity=s.integrity),s.referrerPolicy&&(d.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?d.credentials="include":s.crossOrigin==="anonymous"?d.credentials="omit":d.credentials="same-origin",d}function c(s){if(s.ep)return;s.ep=!0;const d=o(s);fetch(s.href,d)}})();function dv(a){return a&&a.__esModule&&Object.prototype.hasOwnProperty.call(a,"default")?a.default:a}var Uo={exports:{}},yu={};/** + * @license React + * react-jsx-runtime.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Mh;function Q0(){if(Mh)return yu;Mh=1;var a=Symbol.for("react.transitional.element"),i=Symbol.for("react.fragment");function o(c,s,d){var m=null;if(d!==void 0&&(m=""+d),s.key!==void 0&&(m=""+s.key),"key"in s){d={};for(var g in s)g!=="key"&&(d[g]=s[g])}else d=s;return s=d.ref,{$$typeof:a,type:c,key:m,ref:s!==void 0?s:null,props:d}}return yu.Fragment=i,yu.jsx=o,yu.jsxs=o,yu}var Th;function Z0(){return Th||(Th=1,Uo.exports=Q0()),Uo.exports}var T=Z0(),Lo={exports:{}},me={};/** + * @license React + * react.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var wh;function K0(){if(wh)return me;wh=1;var a=Symbol.for("react.transitional.element"),i=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),c=Symbol.for("react.strict_mode"),s=Symbol.for("react.profiler"),d=Symbol.for("react.consumer"),m=Symbol.for("react.context"),g=Symbol.for("react.forward_ref"),y=Symbol.for("react.suspense"),v=Symbol.for("react.memo"),p=Symbol.for("react.lazy"),S=Symbol.iterator;function x(E){return E===null||typeof E!="object"?null:(E=S&&E[S]||E["@@iterator"],typeof E=="function"?E:null)}var M={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},R=Object.assign,C={};function _(E,k,F){this.props=E,this.context=k,this.refs=C,this.updater=F||M}_.prototype.isReactComponent={},_.prototype.setState=function(E,k){if(typeof E!="object"&&typeof E!="function"&&E!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,E,k,"setState")},_.prototype.forceUpdate=function(E){this.updater.enqueueForceUpdate(this,E,"forceUpdate")};function H(){}H.prototype=_.prototype;function Q(E,k,F){this.props=E,this.context=k,this.refs=C,this.updater=F||M}var L=Q.prototype=new H;L.constructor=Q,R(L,_.prototype),L.isPureReactComponent=!0;var Y=Array.isArray,q={H:null,A:null,T:null,S:null,V:null},W=Object.prototype.hasOwnProperty;function P(E,k,F,J,I,fe){return F=fe.ref,{$$typeof:a,type:E,key:k,ref:F!==void 0?F:null,props:fe}}function Z(E,k){return P(E.type,k,void 0,void 0,void 0,E.props)}function re(E){return typeof E=="object"&&E!==null&&E.$$typeof===a}function he(E){var k={"=":"=0",":":"=2"};return"$"+E.replace(/[=:]/g,function(F){return k[F]})}var Ee=/\/+/g;function se(E,k){return typeof E=="object"&&E!==null&&E.key!=null?he(""+E.key):k.toString(36)}function Se(){}function Ce(E){switch(E.status){case"fulfilled":return E.value;case"rejected":throw E.reason;default:switch(typeof E.status=="string"?E.then(Se,Se):(E.status="pending",E.then(function(k){E.status==="pending"&&(E.status="fulfilled",E.value=k)},function(k){E.status==="pending"&&(E.status="rejected",E.reason=k)})),E.status){case"fulfilled":return E.value;case"rejected":throw E.reason}}throw E}function oe(E,k,F,J,I){var fe=typeof E;(fe==="undefined"||fe==="boolean")&&(E=null);var ae=!1;if(E===null)ae=!0;else switch(fe){case"bigint":case"string":case"number":ae=!0;break;case"object":switch(E.$$typeof){case a:case i:ae=!0;break;case p:return ae=E._init,oe(ae(E._payload),k,F,J,I)}}if(ae)return I=I(E),ae=J===""?"."+se(E,0):J,Y(I)?(F="",ae!=null&&(F=ae.replace(Ee,"$&/")+"/"),oe(I,k,F,"",function(je){return je})):I!=null&&(re(I)&&(I=Z(I,F+(I.key==null||E&&E.key===I.key?"":(""+I.key).replace(Ee,"$&/")+"/")+ae)),k.push(I)),1;ae=0;var de=J===""?".":J+":";if(Y(E))for(var Me=0;Me>>1,E=z[$];if(0>>1;$s(J,B))Is(fe,J)?(z[$]=fe,z[I]=B,$=I):(z[$]=J,z[F]=B,$=F);else if(Is(fe,B))z[$]=fe,z[I]=B,$=I;else break e}}return K}function s(z,K){var B=z.sortIndex-K.sortIndex;return B!==0?B:z.id-K.id}if(a.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var d=performance;a.unstable_now=function(){return d.now()}}else{var m=Date,g=m.now();a.unstable_now=function(){return m.now()-g}}var y=[],v=[],p=1,S=null,x=3,M=!1,R=!1,C=!1,_=!1,H=typeof setTimeout=="function"?setTimeout:null,Q=typeof clearTimeout=="function"?clearTimeout:null,L=typeof setImmediate<"u"?setImmediate:null;function Y(z){for(var K=o(v);K!==null;){if(K.callback===null)c(v);else if(K.startTime<=z)c(v),K.sortIndex=K.expirationTime,i(y,K);else break;K=o(v)}}function q(z){if(C=!1,Y(z),!R)if(o(y)!==null)R=!0,W||(W=!0,se());else{var K=o(v);K!==null&&oe(q,K.startTime-z)}}var W=!1,P=-1,Z=5,re=-1;function he(){return _?!0:!(a.unstable_now()-rez&&he());){var $=S.callback;if(typeof $=="function"){S.callback=null,x=S.priorityLevel;var E=$(S.expirationTime<=z);if(z=a.unstable_now(),typeof E=="function"){S.callback=E,Y(z),K=!0;break t}S===o(y)&&c(y),Y(z)}else c(y);S=o(y)}if(S!==null)K=!0;else{var k=o(v);k!==null&&oe(q,k.startTime-z),K=!1}}break e}finally{S=null,x=B,M=!1}K=void 0}}finally{K?se():W=!1}}}var se;if(typeof L=="function")se=function(){L(Ee)};else if(typeof MessageChannel<"u"){var Se=new MessageChannel,Ce=Se.port2;Se.port1.onmessage=Ee,se=function(){Ce.postMessage(null)}}else se=function(){H(Ee,0)};function oe(z,K){P=H(function(){z(a.unstable_now())},K)}a.unstable_IdlePriority=5,a.unstable_ImmediatePriority=1,a.unstable_LowPriority=4,a.unstable_NormalPriority=3,a.unstable_Profiling=null,a.unstable_UserBlockingPriority=2,a.unstable_cancelCallback=function(z){z.callback=null},a.unstable_forceFrameRate=function(z){0>z||125$?(z.sortIndex=B,i(v,z),o(y)===null&&z===o(v)&&(C?(Q(P),P=-1):C=!0,oe(q,B-$))):(z.sortIndex=E,i(y,z),R||M||(R=!0,W||(W=!0,se()))),z},a.unstable_shouldYield=he,a.unstable_wrapCallback=function(z){var K=x;return function(){var B=x;x=K;try{return z.apply(this,arguments)}finally{x=B}}}}(ko)),ko}var Oh;function $0(){return Oh||(Oh=1,Bo.exports=J0()),Bo.exports}var Go={exports:{}},lt={};/** + * @license React + * react-dom.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Nh;function P0(){if(Nh)return lt;Nh=1;var a=os();function i(y){var v="https://react.dev/errors/"+y;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(a)}catch(i){console.error(i)}}return a(),Go.exports=P0(),Go.exports}/** + * @license React + * react-dom-client.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var zh;function F0(){if(zh)return bu;zh=1;var a=$0(),i=os(),o=hv();function c(e){var t="https://react.dev/errors/"+e;if(1E||(e.current=$[E],$[E]=null,E--)}function J(e,t){E++,$[E]=e.current,e.current=t}var I=k(null),fe=k(null),ae=k(null),de=k(null);function Me(e,t){switch(J(ae,t),J(fe,e),J(I,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Im(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Im(t),e=eh(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}F(I),J(I,e)}function je(){F(I),F(fe),F(ae)}function rt(e){e.memoizedState!==null&&J(de,e);var t=I.current,n=eh(t,e.type);t!==n&&(J(fe,e),J(I,n))}function Lt(e){fe.current===e&&(F(I),F(fe)),de.current===e&&(F(de),mu._currentValue=B)}var Ht=Object.prototype.hasOwnProperty,en=a.unstable_scheduleCallback,Cl=a.unstable_cancelCallback,xr=a.unstable_shouldYield,Sr=a.unstable_requestPaint,Mt=a.unstable_now,Er=a.unstable_getCurrentPriorityLevel,el=a.unstable_ImmediatePriority,zs=a.unstable_UserBlockingPriority,Du=a.unstable_NormalPriority,Mp=a.unstable_LowPriority,js=a.unstable_IdlePriority,Tp=a.log,wp=a.unstable_setDisableYieldValue,Sa=null,mt=null;function En(e){if(typeof Tp=="function"&&wp(e),mt&&typeof mt.setStrictMode=="function")try{mt.setStrictMode(Sa,e)}catch{}}var ht=Math.clz32?Math.clz32:Op,Rp=Math.log,_p=Math.LN2;function Op(e){return e>>>=0,e===0?32:31-(Rp(e)/_p|0)|0}var zu=256,ju=4194304;function tl(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194048;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Uu(e,t,n){var l=e.pendingLanes;if(l===0)return 0;var u=0,r=e.suspendedLanes,f=e.pingedLanes;e=e.warmLanes;var h=l&134217727;return h!==0?(l=h&~r,l!==0?u=tl(l):(f&=h,f!==0?u=tl(f):n||(n=h&~e,n!==0&&(u=tl(n))))):(h=l&~r,h!==0?u=tl(h):f!==0?u=tl(f):n||(n=l&~e,n!==0&&(u=tl(n)))),u===0?0:t!==0&&t!==u&&(t&r)===0&&(r=u&-u,n=t&-t,r>=n||r===32&&(n&4194048)!==0)?t:u}function Ea(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Np(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Us(){var e=zu;return zu<<=1,(zu&4194048)===0&&(zu=256),e}function Ls(){var e=ju;return ju<<=1,(ju&62914560)===0&&(ju=4194304),e}function Ar(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function Aa(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Dp(e,t,n,l,u,r){var f=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var h=e.entanglements,A=e.expirationTimes,D=e.hiddenUpdates;for(n=f&~n;0)":-1u||A[l]!==D[u]){var G=` +`+A[l].replace(" at new "," at ");return e.displayName&&G.includes("")&&(G=G.replace("",e.displayName)),G}while(1<=l&&0<=u);break}}}finally{_r=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:"")?Ol(n):""}function Bp(e){switch(e.tag){case 26:case 27:case 5:return Ol(e.type);case 16:return Ol("Lazy");case 13:return Ol("Suspense");case 19:return Ol("SuspenseList");case 0:case 15:return Or(e.type,!1);case 11:return Or(e.type.render,!1);case 1:return Or(e.type,!0);case 31:return Ol("Activity");default:return""}}function Zs(e){try{var t="";do t+=Bp(e),e=e.return;while(e);return t}catch(n){return` +Error generating stack: `+n.message+` +`+n.stack}}function Tt(e){switch(typeof e){case"bigint":case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Ks(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function kp(e){var t=Ks(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),l=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var u=n.get,r=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return u.call(this)},set:function(f){l=""+f,r.call(this,f)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return l},setValue:function(f){l=""+f},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Bu(e){e._valueTracker||(e._valueTracker=kp(e))}function Js(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),l="";return e&&(l=Ks(e)?e.checked?"true":"false":e.value),e=l,e!==n?(t.setValue(e),!0):!1}function ku(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var Gp=/[\n"\\]/g;function wt(e){return e.replace(Gp,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function Nr(e,t,n,l,u,r,f,h){e.name="",f!=null&&typeof f!="function"&&typeof f!="symbol"&&typeof f!="boolean"?e.type=f:e.removeAttribute("type"),t!=null?f==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+Tt(t)):e.value!==""+Tt(t)&&(e.value=""+Tt(t)):f!=="submit"&&f!=="reset"||e.removeAttribute("value"),t!=null?Dr(e,f,Tt(t)):n!=null?Dr(e,f,Tt(n)):l!=null&&e.removeAttribute("value"),u==null&&r!=null&&(e.defaultChecked=!!r),u!=null&&(e.checked=u&&typeof u!="function"&&typeof u!="symbol"),h!=null&&typeof h!="function"&&typeof h!="symbol"&&typeof h!="boolean"?e.name=""+Tt(h):e.removeAttribute("name")}function $s(e,t,n,l,u,r,f,h){if(r!=null&&typeof r!="function"&&typeof r!="symbol"&&typeof r!="boolean"&&(e.type=r),t!=null||n!=null){if(!(r!=="submit"&&r!=="reset"||t!=null))return;n=n!=null?""+Tt(n):"",t=t!=null?""+Tt(t):n,h||t===e.value||(e.value=t),e.defaultValue=t}l=l??u,l=typeof l!="function"&&typeof l!="symbol"&&!!l,e.checked=h?e.checked:!!l,e.defaultChecked=!!l,f!=null&&typeof f!="function"&&typeof f!="symbol"&&typeof f!="boolean"&&(e.name=f)}function Dr(e,t,n){t==="number"&&ku(e.ownerDocument)===e||e.defaultValue===""+n||(e.defaultValue=""+n)}function Nl(e,t,n,l){if(e=e.options,t){t={};for(var u=0;u"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Hr=!1;if(nn)try{var wa={};Object.defineProperty(wa,"passive",{get:function(){Hr=!0}}),window.addEventListener("test",wa,wa),window.removeEventListener("test",wa,wa)}catch{Hr=!1}var Cn=null,Br=null,Yu=null;function nf(){if(Yu)return Yu;var e,t=Br,n=t.length,l,u="value"in Cn?Cn.value:Cn.textContent,r=u.length;for(e=0;e=Oa),of=" ",sf=!1;function ff(e,t){switch(e){case"keyup":return hy.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function df(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Ul=!1;function gy(e,t){switch(e){case"compositionend":return df(t);case"keypress":return t.which!==32?null:(sf=!0,of);case"textInput":return e=t.data,e===of&&sf?null:e;default:return null}}function py(e,t){if(Ul)return e==="compositionend"||!Xr&&ff(e,t)?(e=nf(),Yu=Br=Cn=null,Ul=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=l}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=xf(n)}}function Ef(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Ef(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Af(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=ku(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=ku(e.document)}return t}function Zr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var My=nn&&"documentMode"in document&&11>=document.documentMode,Ll=null,Kr=null,ja=null,Jr=!1;function Cf(e,t,n){var l=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Jr||Ll==null||Ll!==ku(l)||(l=Ll,"selectionStart"in l&&Zr(l)?l={start:l.selectionStart,end:l.selectionEnd}:(l=(l.ownerDocument&&l.ownerDocument.defaultView||window).getSelection(),l={anchorNode:l.anchorNode,anchorOffset:l.anchorOffset,focusNode:l.focusNode,focusOffset:l.focusOffset}),ja&&za(ja,l)||(ja=l,l=Ni(Kr,"onSelect"),0>=f,u-=f,an=1<<32-ht(t)+u|n<r?r:8;var f=z.T,h={};z.T=h,zc(e,!1,t,n);try{var A=u(),D=z.S;if(D!==null&&D(h,A),A!==null&&typeof A=="object"&&typeof A.then=="function"){var G=jy(A,l);$a(e,t,G,xt(e))}else $a(e,t,l,xt(e))}catch(V){$a(e,t,{then:function(){},status:"rejected",reason:V},xt())}finally{K.p=r,z.T=f}}function ky(){}function Nc(e,t,n,l){if(e.tag!==5)throw Error(c(476));var u=Md(e).queue;Cd(e,u,t,B,n===null?ky:function(){return Td(e),n(l)})}function Md(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:B,baseState:B,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:on,lastRenderedState:B},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:on,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Td(e){var t=Md(e).next.queue;$a(e,t,{},xt())}function Dc(){return nt(mu)}function wd(){return Ve().memoizedState}function Rd(){return Ve().memoizedState}function Gy(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=xt();e=wn(n);var l=Rn(t,e,n);l!==null&&(St(l,t,n),Xa(l,t,n)),t={cache:cc()},e.payload=t;return}t=t.return}}function Yy(e,t,n){var l=xt();n={lane:l,revertLane:0,action:n,hasEagerState:!1,eagerState:null,next:null},fi(e)?Od(t,n):(n=Wr(e,t,n,l),n!==null&&(St(n,e,l),Nd(n,t,l)))}function _d(e,t,n){var l=xt();$a(e,t,n,l)}function $a(e,t,n,l){var u={lane:l,revertLane:0,action:n,hasEagerState:!1,eagerState:null,next:null};if(fi(e))Od(t,u);else{var r=e.alternate;if(e.lanes===0&&(r===null||r.lanes===0)&&(r=t.lastRenderedReducer,r!==null))try{var f=t.lastRenderedState,h=r(f,n);if(u.hasEagerState=!0,u.eagerState=h,vt(h,f))return Ju(e,t,u,0),Ue===null&&Ku(),!1}catch{}finally{}if(n=Wr(e,t,u,l),n!==null)return St(n,e,l),Nd(n,t,l),!0}return!1}function zc(e,t,n,l){if(l={lane:2,revertLane:fo(),action:l,hasEagerState:!1,eagerState:null,next:null},fi(e)){if(t)throw Error(c(479))}else t=Wr(e,n,l,2),t!==null&&St(t,e,2)}function fi(e){var t=e.alternate;return e===ge||t!==null&&t===ge}function Od(e,t){Zl=ui=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Nd(e,t,n){if((n&4194048)!==0){var l=t.lanes;l&=e.pendingLanes,n|=l,t.lanes=n,Bs(e,n)}}var di={readContext:nt,use:ri,useCallback:Ye,useContext:Ye,useEffect:Ye,useImperativeHandle:Ye,useLayoutEffect:Ye,useInsertionEffect:Ye,useMemo:Ye,useReducer:Ye,useRef:Ye,useState:Ye,useDebugValue:Ye,useDeferredValue:Ye,useTransition:Ye,useSyncExternalStore:Ye,useId:Ye,useHostTransitionStatus:Ye,useFormState:Ye,useActionState:Ye,useOptimistic:Ye,useMemoCache:Ye,useCacheRefresh:Ye},Dd={readContext:nt,use:ri,useCallback:function(e,t){return st().memoizedState=[e,t===void 0?null:t],e},useContext:nt,useEffect:vd,useImperativeHandle:function(e,t,n){n=n!=null?n.concat([e]):null,si(4194308,4,bd.bind(null,t,e),n)},useLayoutEffect:function(e,t){return si(4194308,4,e,t)},useInsertionEffect:function(e,t){si(4,2,e,t)},useMemo:function(e,t){var n=st();t=t===void 0?null:t;var l=e();if(hl){En(!0);try{e()}finally{En(!1)}}return n.memoizedState=[l,t],l},useReducer:function(e,t,n){var l=st();if(n!==void 0){var u=n(t);if(hl){En(!0);try{n(t)}finally{En(!1)}}}else u=t;return l.memoizedState=l.baseState=u,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:u},l.queue=e,e=e.dispatch=Yy.bind(null,ge,e),[l.memoizedState,e]},useRef:function(e){var t=st();return e={current:e},t.memoizedState=e},useState:function(e){e=wc(e);var t=e.queue,n=_d.bind(null,ge,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:_c,useDeferredValue:function(e,t){var n=st();return Oc(n,e,t)},useTransition:function(){var e=wc(!1);return e=Cd.bind(null,ge,e.queue,!0,!1),st().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var l=ge,u=st();if(we){if(n===void 0)throw Error(c(407));n=n()}else{if(n=t(),Ue===null)throw Error(c(349));(Ae&124)!==0||If(l,t,n)}u.memoizedState=n;var r={value:n,getSnapshot:t};return u.queue=r,vd(td.bind(null,l,r,e),[e]),l.flags|=2048,Jl(9,oi(),ed.bind(null,l,r,n,t),null),n},useId:function(){var e=st(),t=Ue.identifierPrefix;if(we){var n=un,l=an;n=(l&~(1<<32-ht(l)-1)).toString(32)+n,t="«"+t+"R"+n,n=ii++,0ie?(Fe=le,le=null):Fe=le.sibling;var Te=j(O,le,N[ie],X);if(Te===null){le===null&&(le=Fe);break}e&&le&&Te.alternate===null&&t(O,le),w=r(Te,w,ie),ye===null?ee=Te:ye.sibling=Te,ye=Te,le=Fe}if(ie===N.length)return n(O,le),we&&cl(O,ie),ee;if(le===null){for(;ieie?(Fe=le,le=null):Fe=le.sibling;var Qn=j(O,le,Te.value,X);if(Qn===null){le===null&&(le=Fe);break}e&&le&&Qn.alternate===null&&t(O,le),w=r(Qn,w,ie),ye===null?ee=Qn:ye.sibling=Qn,ye=Qn,le=Fe}if(Te.done)return n(O,le),we&&cl(O,ie),ee;if(le===null){for(;!Te.done;ie++,Te=N.next())Te=V(O,Te.value,X),Te!==null&&(w=r(Te,w,ie),ye===null?ee=Te:ye.sibling=Te,ye=Te);return we&&cl(O,ie),ee}for(le=l(le);!Te.done;ie++,Te=N.next())Te=U(le,O,ie,Te.value,X),Te!==null&&(e&&Te.alternate!==null&&le.delete(Te.key===null?ie:Te.key),w=r(Te,w,ie),ye===null?ee=Te:ye.sibling=Te,ye=Te);return e&&le.forEach(function(X0){return t(O,X0)}),we&&cl(O,ie),ee}function De(O,w,N,X){if(typeof N=="object"&&N!==null&&N.type===R&&N.key===null&&(N=N.props.children),typeof N=="object"&&N!==null){switch(N.$$typeof){case x:e:{for(var ee=N.key;w!==null;){if(w.key===ee){if(ee=N.type,ee===R){if(w.tag===7){n(O,w.sibling),X=u(w,N.props.children),X.return=O,O=X;break e}}else if(w.elementType===ee||typeof ee=="object"&&ee!==null&&ee.$$typeof===Z&&jd(ee)===w.type){n(O,w.sibling),X=u(w,N.props),Fa(X,N),X.return=O,O=X;break e}n(O,w);break}else t(O,w);w=w.sibling}N.type===R?(X=il(N.props.children,O.mode,X,N.key),X.return=O,O=X):(X=Pu(N.type,N.key,N.props,null,O.mode,X),Fa(X,N),X.return=O,O=X)}return f(O);case M:e:{for(ee=N.key;w!==null;){if(w.key===ee)if(w.tag===4&&w.stateNode.containerInfo===N.containerInfo&&w.stateNode.implementation===N.implementation){n(O,w.sibling),X=u(w,N.children||[]),X.return=O,O=X;break e}else{n(O,w);break}else t(O,w);w=w.sibling}X=tc(N,O.mode,X),X.return=O,O=X}return f(O);case Z:return ee=N._init,N=ee(N._payload),De(O,w,N,X)}if(oe(N))return ce(O,w,N,X);if(se(N)){if(ee=se(N),typeof ee!="function")throw Error(c(150));return N=ee.call(N),ue(O,w,N,X)}if(typeof N.then=="function")return De(O,w,mi(N),X);if(N.$$typeof===L)return De(O,w,ei(O,N),X);hi(O,N)}return typeof N=="string"&&N!==""||typeof N=="number"||typeof N=="bigint"?(N=""+N,w!==null&&w.tag===6?(n(O,w.sibling),X=u(w,N),X.return=O,O=X):(n(O,w),X=ec(N,O.mode,X),X.return=O,O=X),f(O)):n(O,w)}return function(O,w,N,X){try{Pa=0;var ee=De(O,w,N,X);return $l=null,ee}catch(le){if(le===Ya||le===ni)throw le;var ye=gt(29,le,null,O.mode);return ye.lanes=X,ye.return=O,ye}finally{}}}var Pl=Ud(!0),Ld=Ud(!1),Dt=k(null),Qt=null;function On(e){var t=e.alternate;J(Ze,Ze.current&1),J(Dt,e),Qt===null&&(t===null||Ql.current!==null||t.memoizedState!==null)&&(Qt=e)}function Hd(e){if(e.tag===22){if(J(Ze,Ze.current),J(Dt,e),Qt===null){var t=e.alternate;t!==null&&t.memoizedState!==null&&(Qt=e)}}else Nn()}function Nn(){J(Ze,Ze.current),J(Dt,Dt.current)}function sn(e){F(Dt),Qt===e&&(Qt=null),F(Ze)}var Ze=k(0);function vi(e){for(var t=e;t!==null;){if(t.tag===13){var n=t.memoizedState;if(n!==null&&(n=n.dehydrated,n===null||n.data==="$?"||Co(n)))return t}else if(t.tag===19&&t.memoizedProps.revealOrder!==void 0){if((t.flags&128)!==0)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}function jc(e,t,n,l){t=e.memoizedState,n=n(l,t),n=n==null?t:p({},t,n),e.memoizedState=n,e.lanes===0&&(e.updateQueue.baseState=n)}var Uc={enqueueSetState:function(e,t,n){e=e._reactInternals;var l=xt(),u=wn(l);u.payload=t,n!=null&&(u.callback=n),t=Rn(e,u,l),t!==null&&(St(t,e,l),Xa(t,e,l))},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var l=xt(),u=wn(l);u.tag=1,u.payload=t,n!=null&&(u.callback=n),t=Rn(e,u,l),t!==null&&(St(t,e,l),Xa(t,e,l))},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=xt(),l=wn(n);l.tag=2,t!=null&&(l.callback=t),t=Rn(e,l,n),t!==null&&(St(t,e,n),Xa(t,e,n))}};function Bd(e,t,n,l,u,r,f){return e=e.stateNode,typeof e.shouldComponentUpdate=="function"?e.shouldComponentUpdate(l,r,f):t.prototype&&t.prototype.isPureReactComponent?!za(n,l)||!za(u,r):!0}function kd(e,t,n,l){e=t.state,typeof t.componentWillReceiveProps=="function"&&t.componentWillReceiveProps(n,l),typeof t.UNSAFE_componentWillReceiveProps=="function"&&t.UNSAFE_componentWillReceiveProps(n,l),t.state!==e&&Uc.enqueueReplaceState(t,t.state,null)}function vl(e,t){var n=t;if("ref"in t){n={};for(var l in t)l!=="ref"&&(n[l]=t[l])}if(e=e.defaultProps){n===t&&(n=p({},n));for(var u in e)n[u]===void 0&&(n[u]=e[u])}return n}var gi=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function Gd(e){gi(e)}function Yd(e){console.error(e)}function qd(e){gi(e)}function pi(e,t){try{var n=e.onUncaughtError;n(t.value,{componentStack:t.stack})}catch(l){setTimeout(function(){throw l})}}function Xd(e,t,n){try{var l=e.onCaughtError;l(n.value,{componentStack:n.stack,errorBoundary:t.tag===1?t.stateNode:null})}catch(u){setTimeout(function(){throw u})}}function Lc(e,t,n){return n=wn(n),n.tag=3,n.payload={element:null},n.callback=function(){pi(e,t)},n}function Vd(e){return e=wn(e),e.tag=3,e}function Qd(e,t,n,l){var u=n.type.getDerivedStateFromError;if(typeof u=="function"){var r=l.value;e.payload=function(){return u(r)},e.callback=function(){Xd(t,n,l)}}var f=n.stateNode;f!==null&&typeof f.componentDidCatch=="function"&&(e.callback=function(){Xd(t,n,l),typeof u!="function"&&(Hn===null?Hn=new Set([this]):Hn.add(this));var h=l.stack;this.componentDidCatch(l.value,{componentStack:h!==null?h:""})})}function Xy(e,t,n,l,u){if(n.flags|=32768,l!==null&&typeof l=="object"&&typeof l.then=="function"){if(t=n.alternate,t!==null&&Ba(t,n,u,!0),n=Dt.current,n!==null){switch(n.tag){case 13:return Qt===null?io():n.alternate===null&&ke===0&&(ke=3),n.flags&=-257,n.flags|=65536,n.lanes=u,l===fc?n.flags|=16384:(t=n.updateQueue,t===null?n.updateQueue=new Set([l]):t.add(l),co(e,l,u)),!1;case 22:return n.flags|=65536,l===fc?n.flags|=16384:(t=n.updateQueue,t===null?(t={transitions:null,markerInstances:null,retryQueue:new Set([l])},n.updateQueue=t):(n=t.retryQueue,n===null?t.retryQueue=new Set([l]):n.add(l)),co(e,l,u)),!1}throw Error(c(435,n.tag))}return co(e,l,u),io(),!1}if(we)return t=Dt.current,t!==null?((t.flags&65536)===0&&(t.flags|=256),t.flags|=65536,t.lanes=u,l!==ac&&(e=Error(c(422),{cause:l}),Ha(Rt(e,n)))):(l!==ac&&(t=Error(c(423),{cause:l}),Ha(Rt(t,n))),e=e.current.alternate,e.flags|=65536,u&=-u,e.lanes|=u,l=Rt(l,n),u=Lc(e.stateNode,l,u),hc(e,u),ke!==4&&(ke=2)),!1;var r=Error(c(520),{cause:l});if(r=Rt(r,n),au===null?au=[r]:au.push(r),ke!==4&&(ke=2),t===null)return!0;l=Rt(l,n),n=t;do{switch(n.tag){case 3:return n.flags|=65536,e=u&-u,n.lanes|=e,e=Lc(n.stateNode,l,e),hc(n,e),!1;case 1:if(t=n.type,r=n.stateNode,(n.flags&128)===0&&(typeof t.getDerivedStateFromError=="function"||r!==null&&typeof r.componentDidCatch=="function"&&(Hn===null||!Hn.has(r))))return n.flags|=65536,u&=-u,n.lanes|=u,u=Vd(u),Qd(u,e,n,l),hc(n,u),!1}n=n.return}while(n!==null);return!1}var Zd=Error(c(461)),$e=!1;function We(e,t,n,l){t.child=e===null?Ld(t,null,n,l):Pl(t,e.child,n,l)}function Kd(e,t,n,l,u){n=n.render;var r=t.ref;if("ref"in l){var f={};for(var h in l)h!=="ref"&&(f[h]=l[h])}else f=l;return dl(t),l=bc(e,t,n,f,r,u),h=xc(),e!==null&&!$e?(Sc(e,t,u),fn(e,t,u)):(we&&h&&nc(t),t.flags|=1,We(e,t,l,u),t.child)}function Jd(e,t,n,l,u){if(e===null){var r=n.type;return typeof r=="function"&&!Ir(r)&&r.defaultProps===void 0&&n.compare===null?(t.tag=15,t.type=r,$d(e,t,r,l,u)):(e=Pu(n.type,null,l,t,t.mode,u),e.ref=t.ref,e.return=t,t.child=e)}if(r=e.child,!Vc(e,u)){var f=r.memoizedProps;if(n=n.compare,n=n!==null?n:za,n(f,l)&&e.ref===t.ref)return fn(e,t,u)}return t.flags|=1,e=ln(r,l),e.ref=t.ref,e.return=t,t.child=e}function $d(e,t,n,l,u){if(e!==null){var r=e.memoizedProps;if(za(r,l)&&e.ref===t.ref)if($e=!1,t.pendingProps=l=r,Vc(e,u))(e.flags&131072)!==0&&($e=!0);else return t.lanes=e.lanes,fn(e,t,u)}return Hc(e,t,n,l,u)}function Pd(e,t,n){var l=t.pendingProps,u=l.children,r=e!==null?e.memoizedState:null;if(l.mode==="hidden"){if((t.flags&128)!==0){if(l=r!==null?r.baseLanes|n:n,e!==null){for(u=t.child=e.child,r=0;u!==null;)r=r|u.lanes|u.childLanes,u=u.sibling;t.childLanes=r&~l}else t.childLanes=0,t.child=null;return Fd(e,t,l,n)}if((n&536870912)!==0)t.memoizedState={baseLanes:0,cachePool:null},e!==null&&ti(t,r!==null?r.cachePool:null),r!==null?$f(t,r):gc(),Hd(t);else return t.lanes=t.childLanes=536870912,Fd(e,t,r!==null?r.baseLanes|n:n,n)}else r!==null?(ti(t,r.cachePool),$f(t,r),Nn(),t.memoizedState=null):(e!==null&&ti(t,null),gc(),Nn());return We(e,t,u,n),t.child}function Fd(e,t,n,l){var u=sc();return u=u===null?null:{parent:Qe._currentValue,pool:u},t.memoizedState={baseLanes:n,cachePool:u},e!==null&&ti(t,null),gc(),Hd(t),e!==null&&Ba(e,t,l,!0),null}function yi(e,t){var n=t.ref;if(n===null)e!==null&&e.ref!==null&&(t.flags|=4194816);else{if(typeof n!="function"&&typeof n!="object")throw Error(c(284));(e===null||e.ref!==n)&&(t.flags|=4194816)}}function Hc(e,t,n,l,u){return dl(t),n=bc(e,t,n,l,void 0,u),l=xc(),e!==null&&!$e?(Sc(e,t,u),fn(e,t,u)):(we&&l&&nc(t),t.flags|=1,We(e,t,n,u),t.child)}function Wd(e,t,n,l,u,r){return dl(t),t.updateQueue=null,n=Ff(t,l,n,u),Pf(e),l=xc(),e!==null&&!$e?(Sc(e,t,r),fn(e,t,r)):(we&&l&&nc(t),t.flags|=1,We(e,t,n,r),t.child)}function Id(e,t,n,l,u){if(dl(t),t.stateNode===null){var r=Gl,f=n.contextType;typeof f=="object"&&f!==null&&(r=nt(f)),r=new n(l,r),t.memoizedState=r.state!==null&&r.state!==void 0?r.state:null,r.updater=Uc,t.stateNode=r,r._reactInternals=t,r=t.stateNode,r.props=l,r.state=t.memoizedState,r.refs={},dc(t),f=n.contextType,r.context=typeof f=="object"&&f!==null?nt(f):Gl,r.state=t.memoizedState,f=n.getDerivedStateFromProps,typeof f=="function"&&(jc(t,n,f,l),r.state=t.memoizedState),typeof n.getDerivedStateFromProps=="function"||typeof r.getSnapshotBeforeUpdate=="function"||typeof r.UNSAFE_componentWillMount!="function"&&typeof r.componentWillMount!="function"||(f=r.state,typeof r.componentWillMount=="function"&&r.componentWillMount(),typeof r.UNSAFE_componentWillMount=="function"&&r.UNSAFE_componentWillMount(),f!==r.state&&Uc.enqueueReplaceState(r,r.state,null),Qa(t,l,r,u),Va(),r.state=t.memoizedState),typeof r.componentDidMount=="function"&&(t.flags|=4194308),l=!0}else if(e===null){r=t.stateNode;var h=t.memoizedProps,A=vl(n,h);r.props=A;var D=r.context,G=n.contextType;f=Gl,typeof G=="object"&&G!==null&&(f=nt(G));var V=n.getDerivedStateFromProps;G=typeof V=="function"||typeof r.getSnapshotBeforeUpdate=="function",h=t.pendingProps!==h,G||typeof r.UNSAFE_componentWillReceiveProps!="function"&&typeof r.componentWillReceiveProps!="function"||(h||D!==f)&&kd(t,r,l,f),Tn=!1;var j=t.memoizedState;r.state=j,Qa(t,l,r,u),Va(),D=t.memoizedState,h||j!==D||Tn?(typeof V=="function"&&(jc(t,n,V,l),D=t.memoizedState),(A=Tn||Bd(t,n,A,l,j,D,f))?(G||typeof r.UNSAFE_componentWillMount!="function"&&typeof r.componentWillMount!="function"||(typeof r.componentWillMount=="function"&&r.componentWillMount(),typeof r.UNSAFE_componentWillMount=="function"&&r.UNSAFE_componentWillMount()),typeof r.componentDidMount=="function"&&(t.flags|=4194308)):(typeof r.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=l,t.memoizedState=D),r.props=l,r.state=D,r.context=f,l=A):(typeof r.componentDidMount=="function"&&(t.flags|=4194308),l=!1)}else{r=t.stateNode,mc(e,t),f=t.memoizedProps,G=vl(n,f),r.props=G,V=t.pendingProps,j=r.context,D=n.contextType,A=Gl,typeof D=="object"&&D!==null&&(A=nt(D)),h=n.getDerivedStateFromProps,(D=typeof h=="function"||typeof r.getSnapshotBeforeUpdate=="function")||typeof r.UNSAFE_componentWillReceiveProps!="function"&&typeof r.componentWillReceiveProps!="function"||(f!==V||j!==A)&&kd(t,r,l,A),Tn=!1,j=t.memoizedState,r.state=j,Qa(t,l,r,u),Va();var U=t.memoizedState;f!==V||j!==U||Tn||e!==null&&e.dependencies!==null&&Iu(e.dependencies)?(typeof h=="function"&&(jc(t,n,h,l),U=t.memoizedState),(G=Tn||Bd(t,n,G,l,j,U,A)||e!==null&&e.dependencies!==null&&Iu(e.dependencies))?(D||typeof r.UNSAFE_componentWillUpdate!="function"&&typeof r.componentWillUpdate!="function"||(typeof r.componentWillUpdate=="function"&&r.componentWillUpdate(l,U,A),typeof r.UNSAFE_componentWillUpdate=="function"&&r.UNSAFE_componentWillUpdate(l,U,A)),typeof r.componentDidUpdate=="function"&&(t.flags|=4),typeof r.getSnapshotBeforeUpdate=="function"&&(t.flags|=1024)):(typeof r.componentDidUpdate!="function"||f===e.memoizedProps&&j===e.memoizedState||(t.flags|=4),typeof r.getSnapshotBeforeUpdate!="function"||f===e.memoizedProps&&j===e.memoizedState||(t.flags|=1024),t.memoizedProps=l,t.memoizedState=U),r.props=l,r.state=U,r.context=A,l=G):(typeof r.componentDidUpdate!="function"||f===e.memoizedProps&&j===e.memoizedState||(t.flags|=4),typeof r.getSnapshotBeforeUpdate!="function"||f===e.memoizedProps&&j===e.memoizedState||(t.flags|=1024),l=!1)}return r=l,yi(e,t),l=(t.flags&128)!==0,r||l?(r=t.stateNode,n=l&&typeof n.getDerivedStateFromError!="function"?null:r.render(),t.flags|=1,e!==null&&l?(t.child=Pl(t,e.child,null,u),t.child=Pl(t,null,n,u)):We(e,t,n,u),t.memoizedState=r.state,e=t.child):e=fn(e,t,u),e}function em(e,t,n,l){return La(),t.flags|=256,We(e,t,n,l),t.child}var Bc={dehydrated:null,treeContext:null,retryLane:0,hydrationErrors:null};function kc(e){return{baseLanes:e,cachePool:Yf()}}function Gc(e,t,n){return e=e!==null?e.childLanes&~n:0,t&&(e|=zt),e}function tm(e,t,n){var l=t.pendingProps,u=!1,r=(t.flags&128)!==0,f;if((f=r)||(f=e!==null&&e.memoizedState===null?!1:(Ze.current&2)!==0),f&&(u=!0,t.flags&=-129),f=(t.flags&32)!==0,t.flags&=-33,e===null){if(we){if(u?On(t):Nn(),we){var h=Be,A;if(A=h){e:{for(A=h,h=Vt;A.nodeType!==8;){if(!h){h=null;break e}if(A=Gt(A.nextSibling),A===null){h=null;break e}}h=A}h!==null?(t.memoizedState={dehydrated:h,treeContext:rl!==null?{id:an,overflow:un}:null,retryLane:536870912,hydrationErrors:null},A=gt(18,null,null,0),A.stateNode=h,A.return=t,t.child=A,it=t,Be=null,A=!0):A=!1}A||sl(t)}if(h=t.memoizedState,h!==null&&(h=h.dehydrated,h!==null))return Co(h)?t.lanes=32:t.lanes=536870912,null;sn(t)}return h=l.children,l=l.fallback,u?(Nn(),u=t.mode,h=bi({mode:"hidden",children:h},u),l=il(l,u,n,null),h.return=t,l.return=t,h.sibling=l,t.child=h,u=t.child,u.memoizedState=kc(n),u.childLanes=Gc(e,f,n),t.memoizedState=Bc,l):(On(t),Yc(t,h))}if(A=e.memoizedState,A!==null&&(h=A.dehydrated,h!==null)){if(r)t.flags&256?(On(t),t.flags&=-257,t=qc(e,t,n)):t.memoizedState!==null?(Nn(),t.child=e.child,t.flags|=128,t=null):(Nn(),u=l.fallback,h=t.mode,l=bi({mode:"visible",children:l.children},h),u=il(u,h,n,null),u.flags|=2,l.return=t,u.return=t,l.sibling=u,t.child=l,Pl(t,e.child,null,n),l=t.child,l.memoizedState=kc(n),l.childLanes=Gc(e,f,n),t.memoizedState=Bc,t=u);else if(On(t),Co(h)){if(f=h.nextSibling&&h.nextSibling.dataset,f)var D=f.dgst;f=D,l=Error(c(419)),l.stack="",l.digest=f,Ha({value:l,source:null,stack:null}),t=qc(e,t,n)}else if($e||Ba(e,t,n,!1),f=(n&e.childLanes)!==0,$e||f){if(f=Ue,f!==null&&(l=n&-n,l=(l&42)!==0?1:Cr(l),l=(l&(f.suspendedLanes|n))!==0?0:l,l!==0&&l!==A.retryLane))throw A.retryLane=l,kl(e,l),St(f,e,l),Zd;h.data==="$?"||io(),t=qc(e,t,n)}else h.data==="$?"?(t.flags|=192,t.child=e.child,t=null):(e=A.treeContext,Be=Gt(h.nextSibling),it=t,we=!0,ol=null,Vt=!1,e!==null&&(Ot[Nt++]=an,Ot[Nt++]=un,Ot[Nt++]=rl,an=e.id,un=e.overflow,rl=t),t=Yc(t,l.children),t.flags|=4096);return t}return u?(Nn(),u=l.fallback,h=t.mode,A=e.child,D=A.sibling,l=ln(A,{mode:"hidden",children:l.children}),l.subtreeFlags=A.subtreeFlags&65011712,D!==null?u=ln(D,u):(u=il(u,h,n,null),u.flags|=2),u.return=t,l.return=t,l.sibling=u,t.child=l,l=u,u=t.child,h=e.child.memoizedState,h===null?h=kc(n):(A=h.cachePool,A!==null?(D=Qe._currentValue,A=A.parent!==D?{parent:D,pool:D}:A):A=Yf(),h={baseLanes:h.baseLanes|n,cachePool:A}),u.memoizedState=h,u.childLanes=Gc(e,f,n),t.memoizedState=Bc,l):(On(t),n=e.child,e=n.sibling,n=ln(n,{mode:"visible",children:l.children}),n.return=t,n.sibling=null,e!==null&&(f=t.deletions,f===null?(t.deletions=[e],t.flags|=16):f.push(e)),t.child=n,t.memoizedState=null,n)}function Yc(e,t){return t=bi({mode:"visible",children:t},e.mode),t.return=e,e.child=t}function bi(e,t){return e=gt(22,e,null,t),e.lanes=0,e.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null},e}function qc(e,t,n){return Pl(t,e.child,null,n),e=Yc(t,t.pendingProps.children),e.flags|=2,t.memoizedState=null,e}function nm(e,t,n){e.lanes|=t;var l=e.alternate;l!==null&&(l.lanes|=t),ic(e.return,t,n)}function Xc(e,t,n,l,u){var r=e.memoizedState;r===null?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:l,tail:n,tailMode:u}:(r.isBackwards=t,r.rendering=null,r.renderingStartTime=0,r.last=l,r.tail=n,r.tailMode=u)}function lm(e,t,n){var l=t.pendingProps,u=l.revealOrder,r=l.tail;if(We(e,t,l.children,n),l=Ze.current,(l&2)!==0)l=l&1|2,t.flags|=128;else{if(e!==null&&(e.flags&128)!==0)e:for(e=t.child;e!==null;){if(e.tag===13)e.memoizedState!==null&&nm(e,n,t);else if(e.tag===19)nm(e,n,t);else if(e.child!==null){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;e.sibling===null;){if(e.return===null||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}l&=1}switch(J(Ze,l),u){case"forwards":for(n=t.child,u=null;n!==null;)e=n.alternate,e!==null&&vi(e)===null&&(u=n),n=n.sibling;n=u,n===null?(u=t.child,t.child=null):(u=n.sibling,n.sibling=null),Xc(t,!1,u,n,r);break;case"backwards":for(n=null,u=t.child,t.child=null;u!==null;){if(e=u.alternate,e!==null&&vi(e)===null){t.child=u;break}e=u.sibling,u.sibling=n,n=u,u=e}Xc(t,!0,n,null,r);break;case"together":Xc(t,!1,null,null,void 0);break;default:t.memoizedState=null}return t.child}function fn(e,t,n){if(e!==null&&(t.dependencies=e.dependencies),Ln|=t.lanes,(n&t.childLanes)===0)if(e!==null){if(Ba(e,t,n,!1),(n&t.childLanes)===0)return null}else return null;if(e!==null&&t.child!==e.child)throw Error(c(153));if(t.child!==null){for(e=t.child,n=ln(e,e.pendingProps),t.child=n,n.return=t;e.sibling!==null;)e=e.sibling,n=n.sibling=ln(e,e.pendingProps),n.return=t;n.sibling=null}return t.child}function Vc(e,t){return(e.lanes&t)!==0?!0:(e=e.dependencies,!!(e!==null&&Iu(e)))}function Vy(e,t,n){switch(t.tag){case 3:Me(t,t.stateNode.containerInfo),Mn(t,Qe,e.memoizedState.cache),La();break;case 27:case 5:rt(t);break;case 4:Me(t,t.stateNode.containerInfo);break;case 10:Mn(t,t.type,t.memoizedProps.value);break;case 13:var l=t.memoizedState;if(l!==null)return l.dehydrated!==null?(On(t),t.flags|=128,null):(n&t.child.childLanes)!==0?tm(e,t,n):(On(t),e=fn(e,t,n),e!==null?e.sibling:null);On(t);break;case 19:var u=(e.flags&128)!==0;if(l=(n&t.childLanes)!==0,l||(Ba(e,t,n,!1),l=(n&t.childLanes)!==0),u){if(l)return lm(e,t,n);t.flags|=128}if(u=t.memoizedState,u!==null&&(u.rendering=null,u.tail=null,u.lastEffect=null),J(Ze,Ze.current),l)break;return null;case 22:case 23:return t.lanes=0,Pd(e,t,n);case 24:Mn(t,Qe,e.memoizedState.cache)}return fn(e,t,n)}function am(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps)$e=!0;else{if(!Vc(e,n)&&(t.flags&128)===0)return $e=!1,Vy(e,t,n);$e=(e.flags&131072)!==0}else $e=!1,we&&(t.flags&1048576)!==0&&jf(t,Wu,t.index);switch(t.lanes=0,t.tag){case 16:e:{e=t.pendingProps;var l=t.elementType,u=l._init;if(l=u(l._payload),t.type=l,typeof l=="function")Ir(l)?(e=vl(l,e),t.tag=1,t=Id(null,t,l,e,n)):(t.tag=0,t=Hc(null,t,l,e,n));else{if(l!=null){if(u=l.$$typeof,u===Y){t.tag=11,t=Kd(null,t,l,e,n);break e}else if(u===P){t.tag=14,t=Jd(null,t,l,e,n);break e}}throw t=Ce(l)||l,Error(c(306,t,""))}}return t;case 0:return Hc(e,t,t.type,t.pendingProps,n);case 1:return l=t.type,u=vl(l,t.pendingProps),Id(e,t,l,u,n);case 3:e:{if(Me(t,t.stateNode.containerInfo),e===null)throw Error(c(387));l=t.pendingProps;var r=t.memoizedState;u=r.element,mc(e,t),Qa(t,l,null,n);var f=t.memoizedState;if(l=f.cache,Mn(t,Qe,l),l!==r.cache&&rc(t,[Qe],n,!0),Va(),l=f.element,r.isDehydrated)if(r={element:l,isDehydrated:!1,cache:f.cache},t.updateQueue.baseState=r,t.memoizedState=r,t.flags&256){t=em(e,t,l,n);break e}else if(l!==u){u=Rt(Error(c(424)),t),Ha(u),t=em(e,t,l,n);break e}else{switch(e=t.stateNode.containerInfo,e.nodeType){case 9:e=e.body;break;default:e=e.nodeName==="HTML"?e.ownerDocument.body:e}for(Be=Gt(e.firstChild),it=t,we=!0,ol=null,Vt=!0,n=Ld(t,null,l,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling}else{if(La(),l===u){t=fn(e,t,n);break e}We(e,t,l,n)}t=t.child}return t;case 26:return yi(e,t),e===null?(n=ch(t.type,null,t.pendingProps,null))?t.memoizedState=n:we||(n=t.type,e=t.pendingProps,l=zi(ae.current).createElement(n),l[tt]=t,l[ct]=e,et(l,n,e),Je(l),t.stateNode=l):t.memoizedState=ch(t.type,e.memoizedProps,t.pendingProps,e.memoizedState),null;case 27:return rt(t),e===null&&we&&(l=t.stateNode=uh(t.type,t.pendingProps,ae.current),it=t,Vt=!0,u=Be,Gn(t.type)?(Mo=u,Be=Gt(l.firstChild)):Be=u),We(e,t,t.pendingProps.children,n),yi(e,t),e===null&&(t.flags|=4194304),t.child;case 5:return e===null&&we&&((u=l=Be)&&(l=y0(l,t.type,t.pendingProps,Vt),l!==null?(t.stateNode=l,it=t,Be=Gt(l.firstChild),Vt=!1,u=!0):u=!1),u||sl(t)),rt(t),u=t.type,r=t.pendingProps,f=e!==null?e.memoizedProps:null,l=r.children,So(u,r)?l=null:f!==null&&So(u,f)&&(t.flags|=32),t.memoizedState!==null&&(u=bc(e,t,Ly,null,null,n),mu._currentValue=u),yi(e,t),We(e,t,l,n),t.child;case 6:return e===null&&we&&((e=n=Be)&&(n=b0(n,t.pendingProps,Vt),n!==null?(t.stateNode=n,it=t,Be=null,e=!0):e=!1),e||sl(t)),null;case 13:return tm(e,t,n);case 4:return Me(t,t.stateNode.containerInfo),l=t.pendingProps,e===null?t.child=Pl(t,null,l,n):We(e,t,l,n),t.child;case 11:return Kd(e,t,t.type,t.pendingProps,n);case 7:return We(e,t,t.pendingProps,n),t.child;case 8:return We(e,t,t.pendingProps.children,n),t.child;case 12:return We(e,t,t.pendingProps.children,n),t.child;case 10:return l=t.pendingProps,Mn(t,t.type,l.value),We(e,t,l.children,n),t.child;case 9:return u=t.type._context,l=t.pendingProps.children,dl(t),u=nt(u),l=l(u),t.flags|=1,We(e,t,l,n),t.child;case 14:return Jd(e,t,t.type,t.pendingProps,n);case 15:return $d(e,t,t.type,t.pendingProps,n);case 19:return lm(e,t,n);case 31:return l=t.pendingProps,n=t.mode,l={mode:l.mode,children:l.children},e===null?(n=bi(l,n),n.ref=t.ref,t.child=n,n.return=t,t=n):(n=ln(e.child,l),n.ref=t.ref,t.child=n,n.return=t,t=n),t;case 22:return Pd(e,t,n);case 24:return dl(t),l=nt(Qe),e===null?(u=sc(),u===null&&(u=Ue,r=cc(),u.pooledCache=r,r.refCount++,r!==null&&(u.pooledCacheLanes|=n),u=r),t.memoizedState={parent:l,cache:u},dc(t),Mn(t,Qe,u)):((e.lanes&n)!==0&&(mc(e,t),Qa(t,null,null,n),Va()),u=e.memoizedState,r=t.memoizedState,u.parent!==l?(u={parent:l,cache:l},t.memoizedState=u,t.lanes===0&&(t.memoizedState=t.updateQueue.baseState=u),Mn(t,Qe,l)):(l=r.cache,Mn(t,Qe,l),l!==u.cache&&rc(t,[Qe],n,!0))),We(e,t,t.pendingProps.children,n),t.child;case 29:throw t.pendingProps}throw Error(c(156,t.tag))}function dn(e){e.flags|=4}function um(e,t){if(t.type!=="stylesheet"||(t.state.loading&4)!==0)e.flags&=-16777217;else if(e.flags|=16777216,!mh(t)){if(t=Dt.current,t!==null&&((Ae&4194048)===Ae?Qt!==null:(Ae&62914560)!==Ae&&(Ae&536870912)===0||t!==Qt))throw qa=fc,qf;e.flags|=8192}}function xi(e,t){t!==null&&(e.flags|=4),e.flags&16384&&(t=e.tag!==22?Ls():536870912,e.lanes|=t,ea|=t)}function Wa(e,t){if(!we)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;t!==null;)t.alternate!==null&&(n=t),t=t.sibling;n===null?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var l=null;n!==null;)n.alternate!==null&&(l=n),n=n.sibling;l===null?t||e.tail===null?e.tail=null:e.tail.sibling=null:l.sibling=null}}function He(e){var t=e.alternate!==null&&e.alternate.child===e.child,n=0,l=0;if(t)for(var u=e.child;u!==null;)n|=u.lanes|u.childLanes,l|=u.subtreeFlags&65011712,l|=u.flags&65011712,u.return=e,u=u.sibling;else for(u=e.child;u!==null;)n|=u.lanes|u.childLanes,l|=u.subtreeFlags,l|=u.flags,u.return=e,u=u.sibling;return e.subtreeFlags|=l,e.childLanes=n,t}function Qy(e,t,n){var l=t.pendingProps;switch(lc(t),t.tag){case 31:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return He(t),null;case 1:return He(t),null;case 3:return n=t.stateNode,l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),cn(Qe),je(),n.pendingContext&&(n.context=n.pendingContext,n.pendingContext=null),(e===null||e.child===null)&&(Ua(t)?dn(t):e===null||e.memoizedState.isDehydrated&&(t.flags&256)===0||(t.flags|=1024,Hf())),He(t),null;case 26:return n=t.memoizedState,e===null?(dn(t),n!==null?(He(t),um(t,n)):(He(t),t.flags&=-16777217)):n?n!==e.memoizedState?(dn(t),He(t),um(t,n)):(He(t),t.flags&=-16777217):(e.memoizedProps!==l&&dn(t),He(t),t.flags&=-16777217),null;case 27:Lt(t),n=ae.current;var u=t.type;if(e!==null&&t.stateNode!=null)e.memoizedProps!==l&&dn(t);else{if(!l){if(t.stateNode===null)throw Error(c(166));return He(t),null}e=I.current,Ua(t)?Uf(t):(e=uh(u,l,n),t.stateNode=e,dn(t))}return He(t),null;case 5:if(Lt(t),n=t.type,e!==null&&t.stateNode!=null)e.memoizedProps!==l&&dn(t);else{if(!l){if(t.stateNode===null)throw Error(c(166));return He(t),null}if(e=I.current,Ua(t))Uf(t);else{switch(u=zi(ae.current),e){case 1:e=u.createElementNS("http://www.w3.org/2000/svg",n);break;case 2:e=u.createElementNS("http://www.w3.org/1998/Math/MathML",n);break;default:switch(n){case"svg":e=u.createElementNS("http://www.w3.org/2000/svg",n);break;case"math":e=u.createElementNS("http://www.w3.org/1998/Math/MathML",n);break;case"script":e=u.createElement("div"),e.innerHTML=" - + + - +
diff --git a/webview-ui/index.html b/webview-ui/index.html index c4c575e..6780411 100644 --- a/webview-ui/index.html +++ b/webview-ui/index.html @@ -1,4 +1,5 @@ + @@ -6,7 +7,7 @@ Vite + React + TS - +
diff --git a/webview-ui/package.json b/webview-ui/package.json index b5f7b88..b5b1be7 100644 --- a/webview-ui/package.json +++ b/webview-ui/package.json @@ -4,13 +4,14 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", + "dev": "cross-env VITE_APP_ENV=development vite", + "build": "cross-env VITE_APP_ENV=production tsc -b && vite build", "lint": "eslint .", "preview": "vite preview" }, "dependencies": { "@radix-ui/react-checkbox": "^1.2.3", + "@radix-ui/react-context-menu": "^2.2.12", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.9", "@tailwindcss/vite": "^4.1.4", @@ -28,6 +29,7 @@ "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", + "cross-env": "^7.0.3", "eslint": "^9.22.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.19", diff --git a/webview-ui/pnpm-lock.yaml b/webview-ui/pnpm-lock.yaml index b6f649f..9adc531 100644 --- a/webview-ui/pnpm-lock.yaml +++ b/webview-ui/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@radix-ui/react-checkbox': specifier: ^1.2.3 version: 1.2.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-context-menu': + specifier: ^2.2.12 + version: 2.2.12(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': specifier: ^1.2.0 version: 1.2.0(@types/react@19.1.2)(react@19.1.0) @@ -57,6 +60,9 @@ importers: '@vitejs/plugin-react': specifier: ^4.3.4 version: 4.4.1(vite@6.3.3(@types/node@22.15.2)(jiti@2.4.2)(lightningcss@1.29.2)) + cross-env: + specifier: ^7.0.3 + version: 7.0.3 eslint: specifier: ^9.22.0 version: 9.25.1(jiti@2.4.2) @@ -355,6 +361,21 @@ packages: resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@floating-ui/core@1.7.0': + resolution: {integrity: sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==} + + '@floating-ui/dom@1.7.0': + resolution: {integrity: sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==} + + '@floating-ui/react-dom@2.1.2': + resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.9': + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -408,6 +429,19 @@ packages: '@radix-ui/primitive@1.1.2': resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==} + '@radix-ui/react-arrow@1.1.4': + resolution: {integrity: sha512-qz+fxrqgNxG0dYew5l7qR3c7wdgRu1XVUHGnGYX7rg5HM4p9SWaRmJwfgR3J0SgyUKayLmzQIun+N6rWRgiRKw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-checkbox@1.2.3': resolution: {integrity: sha512-pHVzDYsnaDmBlAuwim45y3soIN8H4R7KbkSVirGhXO+R/kO2OLCe0eucUEbddaTcdMHHdzcIGHtZSMSQlA+apw==} peerDependencies: @@ -443,6 +477,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-context-menu@2.2.12': + resolution: {integrity: sha512-5UFKuTMX8F2/KjHvyqu9IYT8bEtDSCJwwIx1PghBo4jh9S6jJVsceq9xIjqsOVcxsynGwV5eaqPE3n/Cu+DrSA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-context@1.1.2': resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} peerDependencies: @@ -461,6 +508,41 @@ packages: '@types/react': optional: true + '@radix-ui/react-dismissable-layer@1.1.7': + resolution: {integrity: sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.2': + resolution: {integrity: sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.4': + resolution: {integrity: sha512-r2annK27lIW5w9Ho5NyQgqs0MmgZSTIKXWpVCJaLC1q2kZrZkcqnmHkCHMEmv8XLvsLlurKMPT+kbKkRkm/xVA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-id@1.1.1': resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} peerDependencies: @@ -470,6 +552,45 @@ packages: '@types/react': optional: true + '@radix-ui/react-menu@2.1.12': + resolution: {integrity: sha512-+qYq6LfbiGo97Zz9fioX83HCiIYYFNs8zAsVCMQrIakoNYylIzWuoD/anAD3UzvvR6cnswmfRFJFq/zYYq/k7Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.4': + resolution: {integrity: sha512-3p2Rgm/a1cK0r/UVkx5F/K9v/EplfjAeIFCGOPYPO4lZ0jtg4iSQXt/YGTSLWaf4x7NG6Z4+uKFcylcTZjeqDA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.6': + resolution: {integrity: sha512-XmsIl2z1n/TsYFLIdYam2rmFwf9OC/Sh2avkbmVMDuBZIe7hSpM0cYnWPAo7nHOVx8zTuwDZGByfcqLdnzp3Vw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-presence@1.1.4': resolution: {integrity: sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==} peerDependencies: @@ -558,6 +679,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-layout-effect@1.1.1': resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} peerDependencies: @@ -576,6 +706,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-size@1.1.1': resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} peerDependencies: @@ -585,6 +724,9 @@ packages: '@types/react': optional: true + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@rollup/rollup-android-arm-eabi@4.40.0': resolution: {integrity: sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==} cpu: [arm] @@ -877,6 +1019,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.4: + resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} + engines: {node: '>=10'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -926,6 +1072,11 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -949,6 +1100,9 @@ packages: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + electron-to-chromium@1.5.143: resolution: {integrity: sha512-QqklJMOFBMqe46k8iIOwA9l2hz57V2OKMmP5eSWcUvwx+mASAsbU+wkF1pHjn9ZVSBPrsYWr4/W/95y5SwYg2g==} @@ -1074,6 +1228,10 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1335,6 +1493,36 @@ packages: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.6.3: + resolution: {integrity: sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react@19.1.0: resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} engines: {node: '>=0.10.0'} @@ -1411,6 +1599,9 @@ packages: peerDependencies: typescript: '>=4.8.4' + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tw-animate-css@1.2.8: resolution: {integrity: sha512-AxSnYRvyFnAiZCUndS3zQZhNfV/B77ZhJ+O7d3K6wfg/jKJY+yv6ahuyXwnyaYA9UdLqnpCwhTRv9pPTBnPR2g==} @@ -1442,6 +1633,26 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + vite@6.3.3: resolution: {integrity: sha512-5nXH+QsELbFKhsEfWLkHrvgRpTdGJzqOZ+utSdmPTvwHmvU6ITTm3xx+mRusihkcI8GeC7lCDyn3kDtiki9scw==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -1734,6 +1945,23 @@ snapshots: '@eslint/core': 0.13.0 levn: 0.4.1 + '@floating-ui/core@1.7.0': + dependencies: + '@floating-ui/utils': 0.2.9 + + '@floating-ui/dom@1.7.0': + dependencies: + '@floating-ui/core': 1.7.0 + '@floating-ui/utils': 0.2.9 + + '@floating-ui/react-dom@2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@floating-ui/dom': 1.7.0 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@floating-ui/utils@0.2.9': {} + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.6': @@ -1778,6 +2006,15 @@ snapshots: '@radix-ui/primitive@1.1.2': {} + '@radix-ui/react-arrow@1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.2 + '@types/react-dom': 19.1.2(@types/react@19.1.2) + '@radix-ui/react-checkbox@1.2.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 @@ -1812,6 +2049,20 @@ snapshots: optionalDependencies: '@types/react': 19.1.2 + '@radix-ui/react-context-menu@2.2.12(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-menu': 2.1.12(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.2)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.2 + '@types/react-dom': 19.1.2(@types/react@19.1.2) + '@radix-ui/react-context@1.1.2(@types/react@19.1.2)(react@19.1.0)': dependencies: react: 19.1.0 @@ -1824,6 +2075,36 @@ snapshots: optionalDependencies: '@types/react': 19.1.2 + '@radix-ui/react-dismissable-layer@1.1.7(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.2)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.2 + '@types/react-dom': 19.1.2(@types/react@19.1.2) + + '@radix-ui/react-focus-guards@1.1.2(@types/react@19.1.2)(react@19.1.0)': + dependencies: + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.2 + + '@radix-ui/react-focus-scope@1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.2)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.2 + '@types/react-dom': 19.1.2(@types/react@19.1.2) + '@radix-ui/react-id@1.1.1(@types/react@19.1.2)(react@19.1.0)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0) @@ -1831,6 +2112,60 @@ snapshots: optionalDependencies: '@types/react': 19.1.2 + '@radix-ui/react-menu@2.1.12(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/primitive': 1.1.2 + '@radix-ui/react-collection': 1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.7(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-popper': 1.2.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.6(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.7(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slot': 1.2.0(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.2)(react@19.1.0) + aria-hidden: 1.2.4 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-remove-scroll: 2.6.3(@types/react@19.1.2)(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.2 + '@types/react-dom': 19.1.2(@types/react@19.1.2) + + '@radix-ui/react-popper@1.2.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@floating-ui/react-dom': 2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-arrow': 1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.2)(react@19.1.0) + '@radix-ui/rect': 1.1.1 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.2 + '@types/react-dom': 19.1.2(@types/react@19.1.2) + + '@radix-ui/react-portal@1.1.6(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.2 + '@types/react-dom': 19.1.2(@types/react@19.1.2) + '@radix-ui/react-presence@1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0) @@ -1911,6 +2246,13 @@ snapshots: optionalDependencies: '@types/react': 19.1.2 + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.2)(react@19.1.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.2)(react@19.1.0) + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.2 + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.2)(react@19.1.0)': dependencies: react: 19.1.0 @@ -1923,6 +2265,13 @@ snapshots: optionalDependencies: '@types/react': 19.1.2 + '@radix-ui/react-use-rect@1.1.1(@types/react@19.1.2)(react@19.1.0)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.1.0 + optionalDependencies: + '@types/react': 19.1.2 + '@radix-ui/react-use-size@1.1.1(@types/react@19.1.2)(react@19.1.0)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0) @@ -1930,6 +2279,8 @@ snapshots: optionalDependencies: '@types/react': 19.1.2 + '@radix-ui/rect@1.1.1': {} + '@rollup/rollup-android-arm-eabi@4.40.0': optional: true @@ -2199,6 +2550,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.4: + dependencies: + tslib: 2.8.1 + balanced-match@1.0.2: {} brace-expansion@1.1.11: @@ -2246,6 +2601,10 @@ snapshots: convert-source-map@2.0.0: {} + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.6 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -2262,6 +2621,8 @@ snapshots: detect-libc@2.0.4: {} + detect-node-es@1.1.0: {} + electron-to-chromium@1.5.143: {} enhanced-resolve@5.18.1: @@ -2425,6 +2786,8 @@ snapshots: gensync@1.0.0-beta.2: {} + get-nonce@1.0.1: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -2623,6 +2986,33 @@ snapshots: react-refresh@0.17.0: {} + react-remove-scroll-bar@2.3.8(@types/react@19.1.2)(react@19.1.0): + dependencies: + react: 19.1.0 + react-style-singleton: 2.2.3(@types/react@19.1.2)(react@19.1.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.2 + + react-remove-scroll@2.6.3(@types/react@19.1.2)(react@19.1.0): + dependencies: + react: 19.1.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.1.2)(react@19.1.0) + react-style-singleton: 2.2.3(@types/react@19.1.2)(react@19.1.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.1.2)(react@19.1.0) + use-sidecar: 1.1.3(@types/react@19.1.2)(react@19.1.0) + optionalDependencies: + '@types/react': 19.1.2 + + react-style-singleton@2.2.3(@types/react@19.1.2)(react@19.1.0): + dependencies: + get-nonce: 1.0.1 + react: 19.1.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.2 + react@19.1.0: {} resolve-from@4.0.0: {} @@ -2698,6 +3088,8 @@ snapshots: dependencies: typescript: 5.7.3 + tslib@2.8.1: {} + tw-animate-css@1.2.8: {} type-check@0.4.0: @@ -2728,6 +3120,21 @@ snapshots: dependencies: punycode: 2.3.1 + use-callback-ref@1.3.3(@types/react@19.1.2)(react@19.1.0): + dependencies: + react: 19.1.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.2 + + use-sidecar@1.1.3(@types/react@19.1.2)(react@19.1.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.1.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.2 + vite@6.3.3(@types/node@22.15.2)(jiti@2.4.2)(lightningcss@1.29.2): dependencies: esbuild: 0.25.3 diff --git a/webview-ui/src/App.tsx b/webview-ui/src/App.tsx index f4f1635..f6ed595 100644 --- a/webview-ui/src/App.tsx +++ b/webview-ui/src/App.tsx @@ -1,249 +1,264 @@ "use client"; -import { useState, useEffect, useCallback } from "react"; -import { TreeNodeType, TreeView } from "@/components/tree-view"; -import { Button } from "@/components/ui/button"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { X, Coffee, Github, Code } from "lucide-react"; -import { cn } from "@/lib/utils"; +import {useState, useEffect, useCallback, useRef} from "react"; +import {TreeNodeType, TreeView} from "@/components/tree-view"; +import {Button} from "@/components/ui/button"; +import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs"; +import {X, Coffee, Github, Code} from "lucide-react"; +import {cn} from "@/lib/utils"; import Logo from "./components/logo"; +import {SampleTree} from "@/lib/sample-tree.ts"; // Tab definition interface Tab { - id: string; - title: string; - data: TreeNodeType[]; - isWelcome?: boolean; + id: string; + title: string; + data: TreeNodeType[]; + isWelcome?: boolean; } +const isDev = import.meta.env.VITE_APP_ENV === 'development' + export default function TreeViewPage() { - const [isSuccess, setIsSuccess] = useState(false); - - useEffect(() => { - if (isSuccess) { - const timer = setTimeout(() => { - setIsSuccess(false); - }, 2000); - return () => clearTimeout(timer); - } - }, [isSuccess]); - - // start with only the welcome tab - const [tabs, setTabs] = useState([ - { id: "welcome", title: "Welcome", data: [], isWelcome: true }, - ]); - const [activeTab, setActiveTab] = useState("welcome"); - - // add a new tab (replaces old addNewTab / addSampleTab) - const addSampleTab = useCallback((title: string, initialData: TreeNodeType[]) => { - const newId = `tab-${Date.now()}`; - setTabs((prev) => [ - ...prev, - { id: newId, title, data: initialData }, - ]); - setActiveTab(newId); - return newId; - }, []); - - // close logic - const closeTab = useCallback( - (id: string) => { - setTabs((prev) => { - const filtered = prev.filter((t) => t.id !== id); - if (activeTab === id && filtered.length > 0) { - setActiveTab(filtered[filtered.length - 1].id); + const [isSuccess, setIsSuccess] = useState(false); + const renderedOnce = useRef(false); + + useEffect(() => { + if (isSuccess) { + const timer = setTimeout(() => { + setIsSuccess(false); + }, 2000); + return () => clearTimeout(timer); } - return filtered; - }); - }, - [activeTab] - ); - - // update the tree data for a specific tab - const updateTabData = useCallback((id: string, newData: TreeNodeType[]) => { - setTabs((prev) => - prev.map((t) => (t.id === id ? { ...t, data: newData } : t)) + }, [isSuccess]); + + // start with only the welcome tab + const [tabs, setTabs] = useState([ + {id: "welcome", title: "Welcome", data: [], isWelcome: true}, + ]); + const [activeTab, setActiveTab] = useState("welcome"); + + // add a new tab (replaces old addNewTab / addSampleTab) + const addSampleTab = useCallback((title: string, initialData: TreeNodeType[]) => { + const newId = `tab-${Date.now()}`; + setTabs((prev) => [ + ...prev, + {id: newId, title, data: initialData}, + ]); + setActiveTab(newId); + return newId; + }, []); + + // close logic + const closeTab = useCallback( + (id: string) => { + setTabs((prev) => { + const filtered = prev.filter((t) => t.id !== id); + if (activeTab === id && filtered.length > 0) { + setActiveTab(filtered[filtered.length - 1].id); + } + return filtered; + }); + }, + [activeTab] ); - }, []); - - // copy logic (unchanged) - const filterUncheckedNodes = (nodes: TreeNodeType[]): TreeNodeType[] => - nodes - .filter((n) => n.checked || n.indeterminate) - .map((n) => { - const c = { ...n }; - if (c.children) c.children = filterUncheckedNodes(c.children); - delete c.indeterminate; - return c; - }); - - const formatTreeAsText = ( - nodes: TreeNodeType[], - prefix = "" - ): string => { - let out = ""; - nodes.forEach((n, i) => { - const last = i === nodes.length - 1; - const conn = last ? "└──" : "├──"; - out += `${prefix}${conn} ${n.name}\n`; - if (n.children && n.children.length) { - const childPref = prefix + (last ? " " : "│ "); - out += formatTreeAsText(n.children, childPref); - } - }); - return out; - }; - - const handleCopyToClipboard = (data: TreeNodeType[]) => { - const txt = formatTreeAsText(filterUncheckedNodes(data)); - console.log("Copying to clipboard:", txt); - navigator.clipboard.writeText(txt).catch(console.error); - setIsSuccess(true); - }; - - // **NEW**: listen for messages from the extension - useEffect(() => { - const onMessage = (e: MessageEvent) => { - const msg = e.data; - console.log("Received message from extension:", msg); - if (msg.command === "addFolder") { - // derive a tab title from the folder path - const parts = msg.folderPath.replace(/[/\\]$/, "").split(/[/\\]/); - const title = parts[parts.length - 1] || msg.folderPath; - addSampleTab(title, msg.tree as TreeNodeType[]); - } + + // update the tree data for a specific tab + const updateTabData = useCallback((id: string, newData: TreeNodeType[]) => { + setTabs((prev) => + prev.map((t) => (t.id === id ? {...t, data: newData} : t)) + ); + }, []); + + // copy logic (unchanged) + const filterUncheckedNodes = (nodes: TreeNodeType[]): TreeNodeType[] => + nodes + .filter((n) => n.checked || n.indeterminate) + .map((n) => { + const c = {...n}; + if (c.children) c.children = filterUncheckedNodes(c.children); + delete c.indeterminate; + return c; + }); + + const formatTreeAsText = ( + nodes: TreeNodeType[], + prefix = "" + ): string => { + let out = ""; + nodes.forEach((n, i) => { + const last = i === nodes.length - 1; + const conn = last ? "└──" : "├──"; + out += `${prefix}${conn} ${n.name}\n`; + if (n.children && n.children.length) { + const childPref = prefix + (last ? " " : "│ "); + out += formatTreeAsText(n.children, childPref); + } + }); + return out; }; - window.addEventListener("message", onMessage); - return () => window.removeEventListener("message", onMessage); - }, [addSampleTab]); - - return ( -
-
- -
- - {tabs.map((tab) => ( -
- - {tab.title} - {!tab.isWelcome && ( - - )} - -
- ))} -
-
- - {tabs.map((tab) => ( - - {tab.isWelcome ? ( - - ) : ( -
-
- -
-
- updateTabData(tab.id, d)} - /> -
-
- )} -
- ))} -
-
-
- ); + + const handleCopyToClipboard = (data: TreeNodeType[]) => { + const txt = formatTreeAsText(filterUncheckedNodes(data)); + console.log("Copying to clipboard:", txt); + navigator.clipboard.writeText(txt).catch(console.error); + setIsSuccess(true); + }; + + // **NEW**: listen for messages from the extension + useEffect(() => { + const onMessage = (e: MessageEvent) => { + const msg = e.data; + console.log("Received message from extension:", msg); + if (msg.command === "addFolder") { + // derive a tab title from the folder path + const parts = msg.folderPath.replace(/[/\\]$/, "").split(/[/\\]/); + const title = parts[parts.length - 1] || msg.folderPath; + addSampleTab(title, msg.tree as TreeNodeType[]); + } + }; + window.addEventListener("message", onMessage); + + return () => window.removeEventListener("message", onMessage); + }, [addSampleTab]); + + useEffect(() => { + if (isDev && !renderedOnce.current) { + renderedOnce.current = true; + setTimeout(function () { + window.postMessage(SampleTree); + }, 1000); + } + }, []); + + return ( +
+
+ +
+ + {tabs.map((tab) => ( +
+ + {tab.title} + {!tab.isWelcome && ( + + )} + +
+ ))} +
+
+ + {tabs.map((tab) => ( + + {tab.isWelcome ? ( + + ) : ( +
+
+ +
+
+ updateTabData(tab.id, d)} + /> +
+
+ )} +
+ ))} +
+
+
+ ); } // Welcome tab remains unchanged function WelcomeTab() { - return ( -
-
- -
- -

Welcome to JetTreeMark

-

- Instantly generate and copy a beautiful tree view of your project's folders inside VS Code. -

- -
-
-

- Tip: To use this tool, right-click on a folder in your file explorer and - click "Show Tree View" from the context menu. -

-
+ return ( +
+
+ +
+ +

Welcome to JetTreeMark

+

+ Instantly generate and copy a beautiful tree view of your project's folders inside VS Code. +

-
- - - GitHub - - - - - Contribute - - - - - Buy me a coffee - +
+
+

+ Tip: To use this tool, right-click on a folder in your file + explorer and + click "Show Tree View" from the context menu. +

+
+ + +
-
-
- ) + ) } \ No newline at end of file diff --git a/webview-ui/src/components/tree-view.tsx b/webview-ui/src/components/tree-view.tsx index 738a37d..85ab896 100644 --- a/webview-ui/src/components/tree-view.tsx +++ b/webview-ui/src/components/tree-view.tsx @@ -5,6 +5,21 @@ import { useState, useEffect, useRef } from "react" import { Checkbox } from "@/components/ui/checkbox" import { ChevronRight, ChevronDown, Folder, FolderOpen, File } from "lucide-react" import { cn } from "@/lib/utils" +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, + ContextMenuTrigger, +} from "@/components/ui/context-menu" +import { + checkAllChildren, + checkAllFolders, + uncheckAllChildren, + checkWithoutChildren, + checkOnlyFoldersAtLevel, + checkOnlyFilesAtLevel, + checkAllChildrenAtLevel +} from "@/lib/tree-utils" export interface TreeNodeType { id: string @@ -22,6 +37,7 @@ interface TreeViewProps { export const TreeView: React.FC = ({ data, onChange }) => { const [treeData, setTreeData] = useState(data) + const [allExpanded, setAllExpanded] = useState(true) useEffect(() => { setTreeData(data) @@ -91,10 +107,103 @@ export const TreeView: React.FC = ({ data, onChange }) => { onChange(updatedTree) } + // Apply a transformation to a specific node and its children + const applyTransformation = (nodeId: string, transformation: (nodes: TreeNodeType[]) => TreeNodeType[]) => { + const treeCopy = cloneTree(treeData) + + // Find and transform the node with the given ID + const transformNode = (nodes: TreeNodeType[], id: string): TreeNodeType[] => { + return nodes.map(node => { + if (node.id === id) { + // If this is the target node, apply the transformation to its children + if (node.children && node.children.length > 0) { + const transformedChildren = transformation(node.children) + + // Calculate the new state based on children + const allChecked = transformedChildren.every((child) => child.checked) + const noneChecked = transformedChildren.every((child) => !child.checked && !child.indeterminate) + + return { + ...node, + children: transformedChildren, + checked: allChecked, + indeterminate: !allChecked && !noneChecked, + } + } + return node + } else if (node.children && node.children.length > 0) { + // If not the target node, recursively search its children + return { + ...node, + children: transformNode(node.children, id) + } + } + return node + }) + } + + const updatedTree = transformNode(treeCopy, nodeId) + setTreeData(updatedTree) + onChange(updatedTree) + } + + // Apply a transformation to a specific node without affecting its children + const applyNodeTransformation = (nodeId: string, transformation: (node: TreeNodeType) => TreeNodeType) => { + const treeCopy = cloneTree(treeData) + + // Find and transform the node with the given ID + const transformNode = (nodes: TreeNodeType[], id: string): TreeNodeType[] => { + return nodes.map(node => { + if (node.id === id) { + // If this is the target node, apply the transformation + return transformation(node) + } else if (node.children && node.children.length > 0) { + // If not the target node, recursively search its children + return { + ...node, + children: transformNode(node.children, id) + } + } + return node + }) + } + + const updatedTree = transformNode(treeCopy, nodeId) + setTreeData(updatedTree) + onChange(updatedTree) + } + + // Toggle expansion state for all nodes + const toggleAllExpanded = (expanded: boolean) => { + setAllExpanded(expanded) + } + return (
+
+ + +
{treeData.map((node) => ( - + ))}
) @@ -104,9 +213,19 @@ interface TreeNodeProps { node: TreeNodeType level: number onCheck: (nodeId: string, checked: boolean) => void + applyTransformation: (nodeId: string, transformation: (nodes: TreeNodeType[]) => TreeNodeType[]) => void + applyNodeTransformation: (nodeId: string, transformation: (node: TreeNodeType) => TreeNodeType) => void + forceExpanded?: boolean } -const TreeNode: React.FC = ({ node, level, onCheck }) => { +const TreeNode: React.FC = ({ + node, + level, + onCheck, + applyTransformation, + applyNodeTransformation, + forceExpanded +}) => { const [expanded, setExpanded] = useState(true) const checkboxRef = useRef(null) const hasChildren = node.children && node.children.length > 0 @@ -118,6 +237,13 @@ const TreeNode: React.FC = ({ node, level, onCheck }) => { } }, [node.indeterminate]) + // Update expanded state when forceExpanded changes + useEffect(() => { + if (forceExpanded !== undefined) { + setExpanded(forceExpanded) + } + }, [forceExpanded]) + const handleToggle = () => { if (hasChildren) { setExpanded(!expanded) @@ -128,45 +254,99 @@ const TreeNode: React.FC = ({ node, level, onCheck }) => { onCheck(node.id, checked) } + // Context menu handlers + const handleCheckAllChildren = () => { + applyTransformation(node.id, checkAllChildren) + } + + const handleCheckAllFolders = () => { + applyTransformation(node.id, checkAllFolders) + } + + const handleUncheckAllChildren = () => { + applyTransformation(node.id, uncheckAllChildren) + } + + const handleCheckWithoutChildren = () => { + applyNodeTransformation(node.id, checkWithoutChildren) + } + + const handleCheckOnlyFoldersAtLevel = () => { + applyTransformation(node.id, checkOnlyFoldersAtLevel) + } + + const handleCheckOnlyFilesAtLevel = () => { + applyTransformation(node.id, checkOnlyFilesAtLevel) + } + + const handleCheckAllChildrenAtLevel = () => { + applyTransformation(node.id, checkAllChildrenAtLevel) + } + return (
-
-
- {hasChildren ? ( - - ) : ( -
- )} - - - - - {node.type === "folder" ? ( - expanded ? ( - + + +
+
+ {hasChildren ? ( + ) : ( - - ) - ) : ( - - )} - - - {node.name} -
-
+
+ )} + + + + + + {node.type === "folder" ? ( + expanded ? ( + + ) : ( + + ) + ) : ( + + )} + + + {node.name} +
+
+ + + Check All Children + Check All Folders + Uncheck All Children + Check Without Children + + + + Level-Specific Operations + + + Check Only Folders (This Level) + Check Only Files (This Level) + Check All Children (This Level) + + + + setExpanded(true)}>Expand + setExpanded(false)}>Collapse + + {hasChildren && expanded && (
@@ -180,10 +360,18 @@ const TreeNode: React.FC = ({ node, level, onCheck }) => { }} /> {node.children!.map((childNode) => ( - + ))}
)}
) -} \ No newline at end of file +} diff --git a/webview-ui/src/components/ui/context-menu.tsx b/webview-ui/src/components/ui/context-menu.tsx new file mode 100644 index 0000000..08ec121 --- /dev/null +++ b/webview-ui/src/components/ui/context-menu.tsx @@ -0,0 +1,250 @@ +import * as React from "react" +import * as ContextMenuPrimitive from "@radix-ui/react-context-menu" +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function ContextMenu({ + ...props +}: React.ComponentProps) { + return +} + +function ContextMenuTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function ContextMenuGroup({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function ContextMenuPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function ContextMenuSub({ + ...props +}: React.ComponentProps) { + return +} + +function ContextMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function ContextMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + {children} + + + ) +} + +function ContextMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function ContextMenuContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function ContextMenuItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean + variant?: "default" | "destructive" +}) { + return ( + + ) +} + +function ContextMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function ContextMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function ContextMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + ) +} + +function ContextMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function ContextMenuShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ) +} + +export { + ContextMenu, + ContextMenuTrigger, + ContextMenuContent, + ContextMenuItem, + ContextMenuCheckboxItem, + ContextMenuRadioItem, + ContextMenuLabel, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuGroup, + ContextMenuPortal, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuRadioGroup, +} diff --git a/webview-ui/src/index.css b/webview-ui/src/index.css index 7e50bb6..a4c1d31 100644 --- a/webview-ui/src/index.css +++ b/webview-ui/src/index.css @@ -128,4 +128,8 @@ body { @apply bg-background text-foreground; } +} + +.jettreemark-body{ + padding: 0!important; } \ No newline at end of file diff --git a/webview-ui/src/lib/sample-tree.ts b/webview-ui/src/lib/sample-tree.ts new file mode 100644 index 0000000..ecd04f0 --- /dev/null +++ b/webview-ui/src/lib/sample-tree.ts @@ -0,0 +1,90 @@ +export const SampleTree = { + "command": "addFolder", + "folderPath": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app", + "tree": [ + { + "id": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app", + "name": "app", + "type": "folder", + "checked": true, + "indeterminate": false, + "children": [ + { + "id": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app\\favicon.ico", + "name": "favicon.ico", + "type": "file", + "checked": true + }, + { + "id": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app\\fonts", + "name": "fonts", + "type": "folder", + "checked": true, + "indeterminate": false, + "children": [ + { + "id": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app\\fonts\\GeistMonoVF.woff", + "name": "GeistMonoVF.woff", + "type": "file", + "checked": true + }, + { + "id": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app\\fonts\\GeistVF.woff", + "name": "GeistVF.woff", + "type": "file", + "checked": true + }, + { + "id": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app\\fonts\\hhh", + "name": "hhh", + "type": "folder", + "checked": true, + "indeterminate": false, + "children": [] + } + ] + }, + { + "id": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app\\globals.css", + "name": "globals.css", + "type": "file", + "checked": true + }, + { + "id": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app\\layout.js", + "name": "layout.js", + "type": "file", + "checked": true + }, + { + "id": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app\\myFolder", + "name": "myFolder", + "type": "folder", + "checked": true, + "indeterminate": false, + "children": [] + }, + { + "id": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app\\myFolder2", + "name": "myFolder2", + "type": "folder", + "checked": true, + "indeterminate": false, + "children": [] + }, + { + "id": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app\\page.js", + "name": "page.js", + "type": "file", + "checked": true + }, + { + "id": "c:\\Users\\HichemTab\\IdeaProjects\\test-next\\src\\app\\test", + "name": "test", + "type": "file", + "checked": true + } + ] + } + ] +}; \ No newline at end of file diff --git a/webview-ui/src/lib/tree-utils.js b/webview-ui/src/lib/tree-utils.js new file mode 100644 index 0000000..434076f --- /dev/null +++ b/webview-ui/src/lib/tree-utils.js @@ -0,0 +1,101 @@ +// Function to add checked property to all nodes in the tree +export function processTreeData(data) { + return data.map((node) => { + const newNode = { ...node, checked: true }; + if (node.children && node.children.length > 0) { + newNode.children = processTreeData(node.children); + } + return newNode; + }); +} +// Function to filter out unchecked nodes +export function filterUncheckedNodes(nodes) { + return nodes + .filter((node) => node.checked) + .map((node) => { + const newNode = { ...node }; + if (newNode.children) { + newNode.children = filterUncheckedNodes(newNode.children); + } + delete newNode.indeterminate; + return newNode; + }); +} +// Function to format tree as text +export function formatTreeAsText(nodes, prefix = "", isRoot = true) { + let result = isRoot ? "File Structure:\n\n" : ""; + nodes.forEach((node, index) => { + const isLast = index === nodes.length - 1; + const connector = isLast ? "└──" : "├──"; + const nodeType = node.type === "folder" ? "📁" : "📄"; + result += `${prefix}${connector} ${nodeType} ${node.name}\n`; + if (node.children && node.children.length > 0) { + const childPrefix = prefix + (isLast ? " " : "│ "); + result += formatTreeAsText(node.children, childPrefix, false); + } + }); + return result; +} +// Function to check all children of a node +export function checkAllChildren(nodes) { + return nodes.map((node) => { + const newNode = { ...node, checked: true, indeterminate: false }; + if (newNode.children && newNode.children.length > 0) { + newNode.children = checkAllChildren(newNode.children); + } + return newNode; + }); +} +// Function to check all folders in the tree +export function checkAllFolders(nodes) { + return nodes.map((node) => { + const newNode = { ...node }; + if (node.type === "folder") { + newNode.checked = true; + newNode.indeterminate = false; + } + if (newNode.children && newNode.children.length > 0) { + newNode.children = checkAllFolders(newNode.children); + } + return newNode; + }); +} +// Function to uncheck all children of a node +export function uncheckAllChildren(nodes) { + return nodes.map((node) => { + const newNode = { ...node, checked: false, indeterminate: false }; + if (newNode.children && newNode.children.length > 0) { + newNode.children = uncheckAllChildren(newNode.children); + } + return newNode; + }); +} +// Function to check a node without affecting its children +export function checkWithoutChildren(node) { + return { ...node, checked: true, indeterminate: false }; +} +// Function to check only folders at a specific level +export function checkOnlyFoldersAtLevel(nodes) { + return nodes.map((node) => { + const newNode = { ...node }; + newNode.checked = node.type === "folder"; + newNode.indeterminate = false; + return newNode; + }); +} +// Function to check only files at a specific level +export function checkOnlyFilesAtLevel(nodes) { + return nodes.map((node) => { + const newNode = { ...node }; + newNode.checked = node.type === "file"; + newNode.indeterminate = false; + return newNode; + }); +} +// Function to check all children at a specific level +export function checkAllChildrenAtLevel(nodes) { + return nodes.map((node) => { + return { ...node, checked: true, indeterminate: false }; + }); +} +//# sourceMappingURL=tree-utils.js.map \ No newline at end of file diff --git a/webview-ui/src/lib/tree-utils.js.map b/webview-ui/src/lib/tree-utils.js.map new file mode 100644 index 0000000..0ab1ea8 --- /dev/null +++ b/webview-ui/src/lib/tree-utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tree-utils.js","sourceRoot":"","sources":["tree-utils.ts"],"names":[],"mappings":"AAEA,4DAA4D;AAC5D,MAAM,UAAU,eAAe,CAAC,IAAoB;IAChD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACvB,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QAC1C,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,OAAO,CAAC,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACnD,CAAC;QACD,OAAO,OAAO,CAAA;IAChB,CAAC,CAAC,CAAA;AACJ,CAAC;AAEH,yCAAyC;AACvC,MAAM,UAAU,oBAAoB,CAAC,KAAqB;IACxD,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;SAC9B,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,EAAE,CAAA;QAC3B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,OAAO,CAAC,QAAQ,GAAG,oBAAoB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QAC3D,CAAC;QACD,OAAO,OAAO,CAAC,aAAa,CAAA;QAC5B,OAAO,OAAO,CAAA;IAChB,CAAC,CAAC,CAAA;AACN,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,gBAAgB,CAAC,KAAqB,EAAE,MAAM,GAAG,EAAE,EAAE,MAAM,GAAG,IAAI;IAChF,IAAI,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAA;IAEhD,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC5B,MAAM,MAAM,GAAG,KAAK,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAA;QACzC,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAA;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;QAErD,MAAM,IAAI,GAAG,MAAM,GAAG,SAAS,IAAI,QAAQ,IAAI,IAAI,CAAC,IAAI,IAAI,CAAA;QAE5D,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;YACvD,MAAM,IAAI,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,CAAC,CAAA;QAC/D,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,gBAAgB,CAAC,KAAqB;IACpD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,CAAA;QAChE,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpD,OAAO,CAAC,QAAQ,GAAG,gBAAgB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QACvD,CAAC;QACD,OAAO,OAAO,CAAA;IAChB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,eAAe,CAAC,KAAqB;IACnD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,EAAE,CAAA;QAC3B,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC3B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAA;YACtB,OAAO,CAAC,aAAa,GAAG,KAAK,CAAA;QAC/B,CAAC;QAED,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpD,OAAO,CAAC,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QACtD,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,kBAAkB,CAAC,KAAqB;IACtD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,CAAA;QACjE,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpD,OAAO,CAAC,QAAQ,GAAG,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QACzD,CAAC;QACD,OAAO,OAAO,CAAA;IAChB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,oBAAoB,CAAC,IAAkB;IACrD,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,CAAA;AACzD,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,uBAAuB,CAAC,KAAqB;IAC3D,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,EAAE,CAAA;QAC3B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAA;QACxC,OAAO,CAAC,aAAa,GAAG,KAAK,CAAA;QAE7B,OAAO,OAAO,CAAA;IAChB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,qBAAqB,CAAC,KAAqB;IACzD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,EAAE,CAAA;QAC3B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,KAAK,MAAM,CAAA;QACtC,OAAO,CAAC,aAAa,GAAG,KAAK,CAAA;QAE7B,OAAO,OAAO,CAAA;IAChB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,uBAAuB,CAAC,KAAqB;IAC3D,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,OAAO,EAAC,GAAG,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAC,CAAA;IACvD,CAAC,CAAC,CAAA;AACJ,CAAC"} \ No newline at end of file diff --git a/webview-ui/src/lib/tree-utils.ts b/webview-ui/src/lib/tree-utils.ts index bcee158..03500ab 100644 --- a/webview-ui/src/lib/tree-utils.ts +++ b/webview-ui/src/lib/tree-utils.ts @@ -1,4 +1,4 @@ -import { TreeNodeType } from "@/components/tree-view" +import {TreeNodeType} from "@/components/tree-view" // Function to add checked property to all nodes in the tree export function processTreeData(data: TreeNodeType[]) { @@ -10,17 +10,8 @@ export function processTreeData(data: TreeNodeType[]) { return newNode }) } - - // Function to create a new tree with a unique ID - export function createNewTree(name: string, data: TreeNodeType[]) { - return { - id: `tree-${Date.now()}`, - name, - data: processTreeData(data), - } - } - - // Function to filter out unchecked nodes + +// Function to filter out unchecked nodes export function filterUncheckedNodes(nodes: TreeNodeType[]): TreeNodeType[] { return nodes .filter((node) => node.checked) @@ -33,23 +24,96 @@ export function processTreeData(data: TreeNodeType[]) { return newNode }) } - + // Function to format tree as text export function formatTreeAsText(nodes: TreeNodeType[], prefix = "", isRoot = true): string { let result = isRoot ? "File Structure:\n\n" : "" - + nodes.forEach((node, index) => { const isLast = index === nodes.length - 1 const connector = isLast ? "└──" : "├──" const nodeType = node.type === "folder" ? "📁" : "📄" - + result += `${prefix}${connector} ${nodeType} ${node.name}\n` - + if (node.children && node.children.length > 0) { const childPrefix = prefix + (isLast ? " " : "│ ") result += formatTreeAsText(node.children, childPrefix, false) } }) - + return result - } \ No newline at end of file + } + + // Function to check all children of a node + export function checkAllChildren(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes.map((node) => { + const newNode = { ...node, checked: true, indeterminate: false } + if (newNode.children && newNode.children.length > 0) { + newNode.children = checkAllChildren(newNode.children) + } + return newNode + }) + } + + // Function to check all folders in the tree + export function checkAllFolders(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes.map((node) => { + const newNode = { ...node } + if (node.type === "folder") { + newNode.checked = true + newNode.indeterminate = false + } + + if (newNode.children && newNode.children.length > 0) { + newNode.children = checkAllFolders(newNode.children) + } + + return newNode + }) + } + + // Function to uncheck all children of a node + export function uncheckAllChildren(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes.map((node) => { + const newNode = { ...node, checked: false, indeterminate: false } + if (newNode.children && newNode.children.length > 0) { + newNode.children = uncheckAllChildren(newNode.children) + } + return newNode + }) + } + + // Function to check a node without affecting its children + export function checkWithoutChildren(node: TreeNodeType): TreeNodeType { + return { ...node, checked: true, indeterminate: false } + } + + // Function to check only folders at a specific level + export function checkOnlyFoldersAtLevel(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes.map((node) => { + const newNode = { ...node } + newNode.checked = node.type === "folder" + newNode.indeterminate = false + + return newNode + }) + } + + // Function to check only files at a specific level + export function checkOnlyFilesAtLevel(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes.map((node) => { + const newNode = { ...node } + newNode.checked = node.type === "file" + newNode.indeterminate = false + + return newNode + }) + } + + // Function to check all children at a specific level + export function checkAllChildrenAtLevel(nodes: TreeNodeType[]): TreeNodeType[] { + return nodes.map((node) => { + return {...node, checked: true, indeterminate: false} + }) + }