@@ -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