experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(tags): tags card detail view 'add tag' becomes search/add — input filters Available Tags inline, Enter creates if no match

+35 -11
+2 -6
features/tags/home.html
··· 168 168 </div> 169 169 170 170 <div class="detail-section"> 171 - <label class="detail-label">Add Tag</label> 171 + <label class="detail-label">Search or add tag</label> 172 172 <div class="new-tag-row"> 173 - <peek-input class="new-tag-input" placeholder="Enter new tag..."></peek-input> 173 + <peek-input class="new-tag-input" placeholder="Type to filter or create…"></peek-input> 174 174 <peek-button class="add-tag-btn" variant="primary" size="sm">Add</peek-button> 175 175 </div> 176 - </div> 177 - 178 - <div class="detail-section"> 179 - <label class="detail-label">Available Tags</label> 180 176 <div class="available-tags"></div> 181 177 </div> 182 178 </div>
+33 -5
features/tags/home.js
··· 581 581 }); 582 582 }); 583 583 584 - // New tag input in detail view 584 + // Search/add tag input in detail view. Typing filters the 585 + // Available Tags list inline; Enter adds the typed tag (creating it 586 + // if no exact match exists). 585 587 const newTagInput = document.querySelector('.new-tag-input'); 586 588 const addTagBtn = document.querySelector('.add-tag-btn'); 587 589 ··· 590 592 if (e.key === 'Enter') { 591 593 addNewTag(newTagInput.value); 592 594 } 595 + }); 596 + newTagInput.addEventListener('input', () => { 597 + const currentTags = state.editingItem 598 + ? state.itemTags.get(state.editingItem.id) || [] 599 + : []; 600 + renderAvailableTags(currentTags, newTagInput.value); 593 601 }); 594 602 595 603 // Add item button ··· 1546 1554 }; 1547 1555 1548 1556 /** 1549 - * Render available tags in detail view 1557 + * Render available tags in detail view, optionally filtered by `query` 1558 + * (substring, case-insensitive). Used by the search/add input above 1559 + * the list — typing live-filters the available tags so the user can 1560 + * pick an existing one without scrolling, or hit Enter to create. 1550 1561 */ 1551 - const renderAvailableTags = (currentTags) => { 1562 + const renderAvailableTags = (currentTags, query = '') => { 1552 1563 const container = document.querySelector('.available-tags'); 1553 1564 const currentTagIds = new Set(currentTags.map(t => t.id)); 1565 + const q = query.trim().toLowerCase(); 1554 1566 1555 1567 container.innerHTML = ''; 1556 1568 1557 - state.tags.forEach(tag => { 1569 + const matches = q 1570 + ? state.tags.filter(tag => tag.name.toLowerCase().includes(q)) 1571 + : state.tags; 1572 + 1573 + matches.forEach(tag => { 1558 1574 const tagEl = document.createElement('span'); 1559 1575 tagEl.className = 'available-tag'; 1560 1576 if (currentTagIds.has(tag.id)) { ··· 1571 1587 1572 1588 if (state.tags.length === 0) { 1573 1589 container.innerHTML = '<span class="no-tags">No tags available</span>'; 1590 + } else if (matches.length === 0) { 1591 + const hint = document.createElement('span'); 1592 + hint.className = 'no-tags'; 1593 + hint.textContent = q ? `Press Enter to create "${q}"` : 'No tags match'; 1594 + container.appendChild(hint); 1574 1595 } 1575 1596 }; 1576 1597 ··· 1588 1609 tags.push(tag); 1589 1610 state.itemTags.set(state.editingItem.id, tags); 1590 1611 } 1612 + 1613 + // Clear the search/add input so the available-tags list re-renders 1614 + // unfiltered after a successful add — picking a tag is the user's 1615 + // commit, the query is no longer relevant. 1616 + const newTagInput = document.querySelector('.new-tag-input'); 1617 + if (newTagInput) newTagInput.value = ''; 1591 1618 1592 1619 // Re-render detail view tags 1593 1620 renderCurrentTags(tags); ··· 1645 1672 // Add tag to item 1646 1673 await addTag(tag); 1647 1674 1648 - // Clear input 1675 + // Clear input — addTag's renderAvailableTags re-runs without a query 1676 + // because we wipe the input value here before the input event fires. 1649 1677 document.querySelector('.new-tag-input').value = ''; 1650 1678 1651 1679 // Re-render sidebar to show new tag