Skip to content

Commit 5bea20c

Browse files
committed
vibe treak
1 parent 53ffa69 commit 5bea20c

File tree

1 file changed

+125
-11
lines changed

1 file changed

+125
-11
lines changed

vsextension/src/extension.ts

Lines changed: 125 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -877,14 +877,49 @@ function getTreeWebviewContent(treeData: TreeNode, specNames: string[] = [], scr
877877
color: var(--vscode-foreground);
878878
}
879879
880-
.modal-select {
880+
.modal-select, .modal-input {
881881
width: 100%;
882882
padding: 6px;
883883
background: var(--vscode-settings-textInputBackground);
884884
color: var(--vscode-settings-textInputForeground);
885885
border: 1px solid var(--vscode-settings-textInputBorder);
886886
border-radius: 2px;
887887
font-family: inherit;
888+
box-sizing: border-box;
889+
}
890+
891+
.autocomplete-container {
892+
position: relative;
893+
width: 100%;
894+
}
895+
896+
.autocomplete-suggestions {
897+
position: absolute;
898+
top: 100%;
899+
left: 0;
900+
right: 0;
901+
background: var(--vscode-editor-background);
902+
border: 1px solid var(--vscode-panel-border);
903+
border-top: none;
904+
max-height: 150px;
905+
overflow-y: auto;
906+
z-index: 2100;
907+
display: none;
908+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
909+
}
910+
911+
.autocomplete-suggestions.visible {
912+
display: block;
913+
}
914+
915+
.suggestion-item {
916+
padding: 6px 10px;
917+
cursor: pointer;
918+
transition: background-color 0.1s ease;
919+
}
920+
921+
.suggestion-item:hover, .suggestion-item.active {
922+
background-color: var(--vscode-list-hoverBackground);
888923
}
889924
890925
.modal-buttons {
@@ -953,10 +988,11 @@ function getTreeWebviewContent(treeData: TreeNode, specNames: string[] = [], scr
953988
<div class="modal-dialog">
954989
<h3 class="modal-title">Create Project</h3>
955990
<div class="modal-content">
956-
<label for="project-type" class="modal-label">Project Type:</label>
957-
<select id="project-type" class="modal-select">
958-
${specOptions}
959-
</select>
991+
<label for="project-type-input" class="modal-label">Project Type:</label>
992+
<div class="autocomplete-container">
993+
<input type="text" id="project-type-input" class="modal-input" placeholder="Search or select type..." autocomplete="off">
994+
<div id="autocomplete-suggestions" class="autocomplete-suggestions"></div>
995+
</div>
960996
</div>
961997
<div class="modal-buttons">
962998
<button id="modal-cancel" class="modal-button modal-button-secondary">Cancel</button>
@@ -972,13 +1008,18 @@ function getTreeWebviewContent(treeData: TreeNode, specNames: string[] = [], scr
9721008
const popupContent = document.getElementById('popup-content');
9731009
const searchInput = document.getElementById('search-input');
9741010
const createModal = document.getElementById('create-modal');
1011+
const typeInput = document.getElementById('project-type-input');
1012+
const suggestionsContainer = document.getElementById('autocomplete-suggestions');
9751013
const modalCancelBtn = document.getElementById('modal-cancel');
9761014
const modalCreateBtn = document.getElementById('modal-create');
9771015
const expandAllBtn = document.getElementById('expand-all');
9781016
const collapseAllBtn = document.getElementById('collapse-all');
9791017
const scanProjectBtn = document.getElementById('scan-project');
9801018
const createProjectBtn = document.getElementById('create-project');
9811019
1020+
const specNames = ${JSON.stringify(specNames)};
1021+
let activeSuggestionIndex = -1;
1022+
9821023
const scrollToProjectUrl = ${scrollToProjectUrl ? `'${scrollToProjectUrl}'` : 'null'};
9831024
9841025
if (scrollToProjectUrl) {
@@ -1027,6 +1068,75 @@ function getTreeWebviewContent(treeData: TreeNode, specNames: string[] = [], scr
10271068
// Handle create project
10281069
createProjectBtn.addEventListener('click', () => {
10291070
createModal.classList.add('visible');
1071+
typeInput.value = '';
1072+
typeInput.focus();
1073+
renderSuggestions('');
1074+
});
1075+
1076+
// Autocomplete logic
1077+
typeInput.addEventListener('input', (e) => {
1078+
renderSuggestions(e.target.value);
1079+
});
1080+
1081+
typeInput.addEventListener('keydown', (e) => {
1082+
const suggestions = suggestionsContainer.querySelectorAll('.suggestion-item');
1083+
if (e.key === 'ArrowDown') {
1084+
activeSuggestionIndex = Math.min(activeSuggestionIndex + 1, suggestions.length - 1);
1085+
updateActiveSuggestion(suggestions);
1086+
e.preventDefault();
1087+
} else if (e.key === 'ArrowUp') {
1088+
activeSuggestionIndex = Math.max(activeSuggestionIndex - 1, -1);
1089+
updateActiveSuggestion(suggestions);
1090+
e.preventDefault();
1091+
} else if (e.key === 'Enter') {
1092+
if (activeSuggestionIndex >= 0) {
1093+
selectSuggestion(suggestions[activeSuggestionIndex].textContent);
1094+
e.preventDefault();
1095+
}
1096+
}
1097+
});
1098+
1099+
function renderSuggestions(filter) {
1100+
const filteredSpecs = specNames.filter(s => s.toLowerCase().includes(filter.toLowerCase()));
1101+
suggestionsContainer.innerHTML = '';
1102+
activeSuggestionIndex = -1;
1103+
1104+
if (filteredSpecs.length > 0) {
1105+
filteredSpecs.forEach(spec => {
1106+
const item = document.createElement('div');
1107+
item.className = 'suggestion-item';
1108+
item.textContent = spec;
1109+
item.addEventListener('click', () => selectSuggestion(spec));
1110+
suggestionsContainer.appendChild(item);
1111+
});
1112+
suggestionsContainer.classList.add('visible');
1113+
} else {
1114+
suggestionsContainer.classList.remove('visible');
1115+
}
1116+
}
1117+
1118+
function updateActiveSuggestion(suggestions) {
1119+
suggestions.forEach((s, i) => {
1120+
if (i === activeSuggestionIndex) {
1121+
s.classList.add('active');
1122+
s.scrollIntoView({ block: 'nearest' });
1123+
} else {
1124+
s.classList.remove('active');
1125+
}
1126+
});
1127+
}
1128+
1129+
function selectSuggestion(spec) {
1130+
typeInput.value = spec;
1131+
suggestionsContainer.classList.remove('visible');
1132+
activeSuggestionIndex = -1;
1133+
}
1134+
1135+
// Close suggestions when clicking outside
1136+
document.addEventListener('click', (e) => {
1137+
if (!typeInput.contains(e.target) && !suggestionsContainer.contains(e.target)) {
1138+
suggestionsContainer.classList.remove('visible');
1139+
}
10301140
});
10311141
10321142
// Handle search
@@ -1079,12 +1189,16 @@ function getTreeWebviewContent(treeData: TreeNode, specNames: string[] = [], scr
10791189
});
10801190
10811191
modalCreateBtn.addEventListener('click', () => {
1082-
const projectType = document.getElementById('project-type').value;
1083-
vscode.postMessage({
1084-
command: 'createProject',
1085-
projectType: projectType
1086-
});
1087-
createModal.classList.remove('visible');
1192+
const projectType = typeInput.value;
1193+
if (projectType) {
1194+
vscode.postMessage({
1195+
command: 'createProject',
1196+
projectType: projectType
1197+
});
1198+
createModal.classList.remove('visible');
1199+
} else {
1200+
typeInput.focus();
1201+
}
10881202
});
10891203
10901204
// Close modal on escape

0 commit comments

Comments
 (0)