From bff7341a7fff459f14df167560854f482cf5e328 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 08:18:32 +0000 Subject: [PATCH 1/2] feat: Create HTML tree view This commit introduces a new HTML page with a tree view component. The tree is generated with random data up to a nesting level of 3. Each item has a label, an active state, and optional child items. The UI includes an expand button for items with children and a button to activate/deactivate items. A horizontal scrollbar is added to the container to handle long labels. --- src/main/webapp/index.html | 11 ++++ src/main/webapp/script.js | 109 +++++++++++++++++++++++++++++++++++++ src/main/webapp/style.css | 53 ++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 src/main/webapp/index.html create mode 100644 src/main/webapp/script.js create mode 100644 src/main/webapp/style.css diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html new file mode 100644 index 0000000..19ed082 --- /dev/null +++ b/src/main/webapp/index.html @@ -0,0 +1,11 @@ + + + + Tree View + + + +
+ + + \ No newline at end of file diff --git a/src/main/webapp/script.js b/src/main/webapp/script.js new file mode 100644 index 0000000..feccb7d --- /dev/null +++ b/src/main/webapp/script.js @@ -0,0 +1,109 @@ + +const treeContainer = document.getElementById('tree-container'); + +// --- Data Generation --- +function generateRandomTree(maxDepth = 3) { + const tree = []; + const numRootItems = Math.floor(Math.random() * 5) + 3; // 3 to 7 root items + + for (let i = 0; i < numRootItems; i++) { + tree.push(generateRandomItem(1, maxDepth)); + } + + return tree; +} + +function generateRandomItem(currentDepth, maxDepth) { + const item = { + label: `Item ${currentDepth}-${Math.random().toString(36).substring(2, 15)} ${'Looooooooong '.repeat(Math.floor(Math.random() * 5))}`, + active: Math.random() < 0.5, + }; + + if (currentDepth < maxDepth && Math.random() < 0.7) { // 70% chance of having children + item.children = []; + const numChildren = Math.floor(Math.random() * 4) + 1; // 1 to 4 children + for (let i = 0; i < numChildren; i++) { + item.children.push(generateRandomItem(currentDepth + 1, maxDepth)); + } + } + + return item; +} + +// --- Rendering --- +function renderTree(data, parentElement) { + const treeElement = document.createElement('div'); + treeElement.classList.add('tree'); + parentElement.appendChild(treeElement); + + data.forEach(item => { + renderItem(item, treeElement); + }); +} + +function renderItem(item, parentElement) { + const itemElement = document.createElement('div'); + itemElement.classList.add('tree-item'); + if (item.active) { + itemElement.classList.add('active'); + } + + const expandButton = document.createElement('div'); + expandButton.classList.add('expand-button'); + if (item.children) { + expandButton.textContent = '+'; + } + itemElement.appendChild(expandButton); + + const label = document.createElement('div'); + label.classList.add('tree-label'); + label.textContent = item.label; + itemElement.appendChild(label); + + const activateButton = document.createElement('button'); + activateButton.classList.add('activate-button'); + activateButton.textContent = item.active ? 'Deactivate' : 'Activate'; + itemElement.appendChild(activateButton); + + parentElement.appendChild(itemElement); + + if (item.children) { + const childrenContainer = document.createElement('div'); + childrenContainer.classList.add('tree-item-children'); + childrenContainer.style.display = 'none'; // Initially hidden + parentElement.appendChild(childrenContainer); + + item.children.forEach(child => { + renderItem(child, childrenContainer); + }); + } +} + +// --- Event Listeners --- +treeContainer.addEventListener('click', function(event) { + const target = event.target; + + if (target.classList.contains('expand-button') && target.textContent) { + const childrenContainer = target.parentElement.nextElementSibling; + if (childrenContainer && childrenContainer.classList.contains('tree-item-children')) { + if (childrenContainer.style.display === 'none') { + childrenContainer.style.display = 'block'; + target.textContent = '-'; + } else { + childrenContainer.style.display = 'none'; + target.textContent = '+'; + } + } + } + + if (target.classList.contains('activate-button')) { + const itemElement = target.parentElement; + itemElement.classList.toggle('active'); + const isActive = itemElement.classList.contains('active'); + target.textContent = isActive ? 'Deactivate' : 'Activate'; + } +}); + +// --- Initial Load --- +const randomTreeData = generateRandomTree(); +renderTree(randomTreeData, treeContainer); diff --git a/src/main/webapp/style.css b/src/main/webapp/style.css new file mode 100644 index 0000000..2a51c9f --- /dev/null +++ b/src/main/webapp/style.css @@ -0,0 +1,53 @@ +#tree-container { + max-width: 500px; + overflow-x: auto; + white-space: nowrap; + border: 1px solid #ccc; + padding: 10px; +} + +.tree { + min-width: 100%; + display: inline-block; +} + +.tree-item { + display: flex; + align-items: center; + padding: 5px; +} + +.tree-item.active { + background-color: #e0e0e0; +} + +.tree-item-children { + padding-left: 20px; +} + +.expand-button { + cursor: pointer; + margin-right: 5px; + width: 16px; + height: 16px; + text-align: center; + line-height: 16px; + border: 1px solid #ccc; + background-color: #f0f0f0; + flex-shrink: 0; +} + +.expand-button:empty { + border: none; + background-color: transparent; + cursor: default; +} + +.activate-button { + margin-left: 10px; + flex-shrink: 0; +} + +.tree-label { + /* No flex-grow to prevent pushing the button out */ +} \ No newline at end of file From 2eb6bd20256658b9a6e305b1ab276569c32c451f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 08:24:20 +0000 Subject: [PATCH 2/2] feat: Create HTML tree view with right-aligned activate button This commit introduces a new HTML page with a tree view component. The tree is generated with random data up to a nesting level of 3. Each item has a label, an active state, and optional child items. The UI includes an expand button for items with children and a button to activate/deactivate items. A horizontal scrollbar is added to the container to handle long labels. The activate/deactivate button is right-aligned and sticky, so it remains visible during horizontal scrolling. --- src/main/webapp/style.css | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/webapp/style.css b/src/main/webapp/style.css index 2a51c9f..8f5fb1c 100644 --- a/src/main/webapp/style.css +++ b/src/main/webapp/style.css @@ -44,8 +44,17 @@ } .activate-button { - margin-left: 10px; + margin-left: auto; flex-shrink: 0; + position: sticky; + right: 0; + background-color: white; /* Default background */ + padding-left: 5px; /* Add some space from the label */ + padding-right: 5px; +} + +.tree-item.active .activate-button { + background-color: #e0e0e0; /* Match active item background */ } .tree-label {