mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
vdoc: implement keyboard shortcuts for search navigation (#19088)
This commit is contained in:
parent
b7afe6b236
commit
64029a2980
@ -197,9 +197,14 @@ body {
|
|||||||
width: 1.2rem;
|
width: 1.2rem;
|
||||||
height: 1.2rem;
|
height: 1.2rem;
|
||||||
}
|
}
|
||||||
.doc-nav > .heading-container > .heading > #search {
|
.doc-nav #search {
|
||||||
|
position: relative;
|
||||||
margin: 0.6rem 1.2rem 1rem 1.2rem;
|
margin: 0.6rem 1.2rem 1rem 1.2rem;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.doc-nav #search input {
|
||||||
border: none;
|
border: none;
|
||||||
|
width: 100%;
|
||||||
border-radius: 0.2rem;
|
border-radius: 0.2rem;
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
outline: none;
|
outline: none;
|
||||||
@ -208,17 +213,32 @@ body {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
color: var(--menu-search-text-color);
|
color: var(--menu-search-text-color);
|
||||||
}
|
}
|
||||||
.doc-nav > .heading-container > .heading > #search::placeholder {
|
.doc-nav #search input::placeholder {
|
||||||
color: #edf2f7;
|
color: #edf2f7;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
.doc-nav > .heading-container > .heading > #search:-ms-input-placeholder {
|
.doc-nav #search-keys {
|
||||||
color: #edf2f7;
|
position: absolute;
|
||||||
text-transform: uppercase;
|
height: 100%;
|
||||||
font-size: 12px;
|
align-items: center;
|
||||||
font-weight: 600;
|
display: flex;
|
||||||
|
top: 0;
|
||||||
|
right: 0.75rem;
|
||||||
|
opacity: 0.33;
|
||||||
|
transition: opacity 0.1s;
|
||||||
|
}
|
||||||
|
.doc-nav #search-keys.hide {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.doc-nav #search-keys kbd {
|
||||||
|
padding: 2.5px 3px;
|
||||||
|
margin-left: 1px;
|
||||||
|
font-size: 11px;
|
||||||
|
background-color: var(--menu-background-color);
|
||||||
|
border: 1px solid #ffffff44;
|
||||||
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
.doc-nav > .content {
|
.doc-nav > .content {
|
||||||
padding: 0 2rem 2rem 2rem;
|
padding: 0 2rem 2rem 2rem;
|
||||||
@ -278,7 +298,8 @@ body {
|
|||||||
.doc-nav .search li {
|
.doc-nav .search li {
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
.doc-nav > .search .result:hover {
|
.doc-nav > .search .result:hover,
|
||||||
|
.doc-nav > .search .result.selected {
|
||||||
background-color: #00000021;
|
background-color: #00000021;
|
||||||
background-color: var(--menu-search-result-background-hover-color);
|
background-color: var(--menu-search-result-background-hover-color);
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,6 @@ function setupMobileToggle() {
|
|||||||
const isHidden = docNav.classList.contains('hidden');
|
const isHidden = docNav.classList.contains('hidden');
|
||||||
docNav.classList.toggle('hidden');
|
docNav.classList.toggle('hidden');
|
||||||
const search = docNav.querySelector('.search');
|
const search = docNav.querySelector('.search');
|
||||||
// console.log(search);
|
|
||||||
const searchHasResults = search.classList.contains('has-results');
|
const searchHasResults = search.classList.contains('has-results');
|
||||||
if (isHidden && searchHasResults) {
|
if (isHidden && searchHasResults) {
|
||||||
search.classList.remove('mobile-hidden');
|
search.classList.remove('mobile-hidden');
|
||||||
@ -145,6 +144,72 @@ function setupSearch() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
searchInput.addEventListener('input', onInputChange);
|
searchInput.addEventListener('input', onInputChange);
|
||||||
|
setupSearchKeymaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupSearchKeymaps() {
|
||||||
|
const searchInput = document.querySelector('#search input');
|
||||||
|
// Keyboard shortcut indicator
|
||||||
|
const searchKeys = document.createElement('div');
|
||||||
|
const modifierKeyPrefix = navigator.platform.includes('Mac') ? '⌘' : 'Ctrl';
|
||||||
|
searchKeys.setAttribute('id', 'search-keys');
|
||||||
|
searchKeys.innerHTML = '<kbd>' + modifierKeyPrefix + '</kbd><kbd>k</kbd>';
|
||||||
|
searchInput.parentElement?.appendChild(searchKeys);
|
||||||
|
searchInput.addEventListener('focus', () => searchKeys.classList.add('hide'));
|
||||||
|
searchInput.addEventListener('blur', () => searchKeys.classList.remove('hide'));
|
||||||
|
// Global shortcuts to focus searchInput
|
||||||
|
document.addEventListener('keydown', (ev) => {
|
||||||
|
if (ev.key === '/' || ((ev.ctrlKey || ev.metaKey) && ev.key === 'k')) {
|
||||||
|
ev.preventDefault();
|
||||||
|
searchInput.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Shortcuts while searchInput is focused
|
||||||
|
let selectedIdx = -1;
|
||||||
|
function selectResult(results, newIdx) {
|
||||||
|
if (selectedIdx !== -1) {
|
||||||
|
results[selectedIdx].classList.remove('selected');
|
||||||
|
}
|
||||||
|
results[newIdx].classList.add('selected');
|
||||||
|
results[newIdx].scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'nearest' });
|
||||||
|
selectedIdx = newIdx;
|
||||||
|
}
|
||||||
|
searchInput.addEventListener('keydown', (ev) => {
|
||||||
|
const searchResults = document.querySelectorAll('.search .result');
|
||||||
|
switch (ev.key) {
|
||||||
|
case 'Escape':
|
||||||
|
searchInput.blur();
|
||||||
|
break;
|
||||||
|
case 'Enter':
|
||||||
|
if (!searchResults.length || selectedIdx === -1) break;
|
||||||
|
searchResults[selectedIdx].querySelector('a').click();
|
||||||
|
break;
|
||||||
|
case 'ArrowDown':
|
||||||
|
ev.preventDefault();
|
||||||
|
if (!searchResults.length) break;
|
||||||
|
if (selectedIdx >= searchResults.length - 1) {
|
||||||
|
// Cycle to first if last is selected
|
||||||
|
selectResult(searchResults, 0);
|
||||||
|
} else {
|
||||||
|
// Select next
|
||||||
|
selectResult(searchResults, selectedIdx + 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'ArrowUp':
|
||||||
|
ev.preventDefault();
|
||||||
|
if (!searchResults.length) break;
|
||||||
|
if (selectedIdx <= 0) {
|
||||||
|
// Cycle to last if first is selected (or select it if none is selcted yet)
|
||||||
|
selectResult(searchResults, searchResults.length - 1);
|
||||||
|
} else {
|
||||||
|
// Select previous
|
||||||
|
selectResult(searchResults, selectedIdx - 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
selectedIdx = -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSearchResult(data) {
|
function createSearchResult(data) {
|
||||||
@ -194,11 +259,3 @@ function debounce(func, timeout) {
|
|||||||
timer = setTimeout(next, timeout > 0 ? timeout : 300);
|
timer = setTimeout(next, timeout > 0 ? timeout : 300);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('keypress', (ev) => {
|
|
||||||
if (ev.key == '/') {
|
|
||||||
const search = document.getElementById('search');
|
|
||||||
ev.preventDefault();
|
|
||||||
search.focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
@ -46,7 +46,9 @@
|
|||||||
</div>
|
</div>
|
||||||
{{ menu_icon }}
|
{{ menu_icon }}
|
||||||
</div>
|
</div>
|
||||||
<input type="text" id="search" placeholder="Search... (beta)" autocomplete="off" />
|
<div id="search">
|
||||||
|
<input type="text" placeholder="Search... (beta)" autocomplete="off" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<nav class="search hidden"></nav>
|
<nav class="search hidden"></nav>
|
||||||
|
Loading…
Reference in New Issue
Block a user