Skip to content

Commit

Permalink
new: Revamped autocomplete UX/UI on search bar
Browse files Browse the repository at this point in the history
features:
-smooth animations/transitions
-tab to auto-completion
-theme-aware
-search bar position aware

new: All outlines are accent colored now
new: We now blur background automatically when autocomplete suggestions are shown
dev: Prevent case-sensitive suggestions by converting all to lowercase
dev: Prevent autocomplete suggestions from causing excessive layout shifts
dev: Do not tab-select search button
dev: Rewritten some code to be more readable
  • Loading branch information
lscambo13 committed Jan 13, 2024
1 parent 52f63e8 commit 10a9ced
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 87 deletions.
19 changes: 9 additions & 10 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
});
}
</script> -->
<link rel="manifest" href="manifest.json?v=1703602562288">
<link rel="icon" type="image/x-icon" href="./favicon.ico?v=1703602562288">
<link rel="manifest" href="manifest.json?v=1703602562289">
<link rel="icon" type="image/x-icon" href="./favicon.ico?v=1703602562289">
<title>Search &bull; Casa Mia</title>
<meta name="theme-color" content="black">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
Expand All @@ -29,10 +29,10 @@
rel="stylesheet" />
<link rel="stylesheet" href="./icons.css" />
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css?v=1703602562288">
<link rel="stylesheet" href="./animations.css?v=1703602562288">
<link rel="stylesheet" href="./style.css?v=1703602562288" />
<script src="./index.js?v=1703602562288" type="module"></script>
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css?v=1703602562289">
<link rel="stylesheet" href="./animations.css?v=1703602562289">
<link rel="stylesheet" href="./style.css?v=1703602562289" />
<script src="./index.js?v=1703602562289" type="module"></script>
</head>

<body>
Expand Down Expand Up @@ -64,16 +64,15 @@ <h1 id="widget-2" class="widget-slide brush-text-style-1 has-shadow">Welcome</h1
</div><i id="right-arrow" class="arrows fa fa-caret-right"></i>
</div>
<div class="search" id="searchbar">
<div id="searchBarFocusMode" class="searchBarFocusMode"></div>
<div id="searchContainer" class="searchContainer">
<input title="Search" type="search" class="searchTerm" id="searchTerm"
placeholder="What's on your mind?" name="casamia-search" autocomplete="off" tabindex="1">
<button type="submit" class="searchButton" id="search-btn" title="Search the web" tabindex="1">
<button type="submit" class="searchButton" id="search-btn" title="Search the web">
<i id="search-btn-icon" class="fa fa-google"></i>
</button>
</div>
<div class="searchTermPlaceholder" id="searchTermPlaceholder">
<span class="searchTermPlaceholderItem" id="searchTermPlaceholderItem"></span>
</div>
<div class="autofillContainer" id="autofillContainer"></div>
</div>
<div id="bookmarks" class="flex-sub-container-horizontal disable-select">
<div id="movies-search" class="predefined-bookmark clickable" tabindex="1">
Expand Down
13 changes: 10 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
toggleArrows,
changeSlide,
addEventListenerOnTag,
getSearchTerm,
} from './js_modules/utils.js';
import { displayLoading, hideLoading } from './js_modules/loading_spinner.js';
import { changeGlow } from './js_modules/colors.js';
Expand Down Expand Up @@ -210,9 +211,13 @@ addEventListenerOnID('movies-search', 'click', Search.movies);
addEventListenerOnID('tv-search', 'click', Search.tv);
addEventListenerOnID('games-search', 'click', Search.games);
addEventListenerOnID('ebooks-search', 'click', Search.ebooks);
addEventListenerOnID('searchTerm', 'input', Search.switchToCLI);
addEventListenerOnID('searchTerm', 'input', Search.processSearchboxInput);
addEventListenerOnID('searchTerm', 'click', () => {
const x = new InputEvent('input');
getSearchTerm().dispatchEvent(x);
});
addEventListenerOnID('searchBarFocusMode', 'click', Search.hideSearchBG);
addEventListenerOnID('searchTerm', 'keypress', Search.enterToSearch);
addEventListenerOnID('searchTermPlaceholderItem', 'click', Search.autofill);
addEventListenerOnID('fetch-bookmarks-btn', 'click', fetchBookmarks);

addEventListenerOnID('left-arrow', 'click', (event) => {
Expand Down Expand Up @@ -262,9 +267,11 @@ const pressAndHold = () => {
const validElements = ['gradient_overlay',
'wrap',
'bookmarks',
'autofillContainer',
'flex-main-container-vertical',
'subtitle',
'footer'];
'footer',
];
if (
validElements.includes(x)
) {
Expand Down
27 changes: 12 additions & 15 deletions js_modules/load_preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -374,60 +374,57 @@ export function defaultSearchEngine(value) {

function searchbarTheme(value) {
const searchContainer = document.getElementById('searchContainer');
const searchAutofill = document.getElementById('searchTermPlaceholderItem');


sessionStorage.setItem('searchbar-color-theme-drop', value);
switch (value) {
case 'glass': {
searchContainer.classList.add('searchbox-style-glass');
searchContainer.classList.remove('searchbox-style-light');
searchContainer.classList.remove('searchbox-style-dark');

searchAutofill.classList.add('searchbox-style-glass');
searchAutofill.classList.remove('searchbox-style-light');
searchAutofill.classList.remove('searchbox-style-dark');
break;
};
case 'light': {
searchContainer.classList.remove('searchbox-style-glass');
searchContainer.classList.add('searchbox-style-light');
searchContainer.classList.remove('searchbox-style-dark');

searchAutofill.classList.remove('searchbox-style-glass');
searchAutofill.classList.add('searchbox-style-light');
searchAutofill.classList.remove('searchbox-style-dark');
break;
};
case 'dark': {
searchContainer.classList.remove('searchbox-style-glass');
searchContainer.classList.remove('searchbox-style-light');
searchContainer.classList.add('searchbox-style-dark');

searchAutofill.classList.remove('searchbox-style-glass');
searchAutofill.classList.remove('searchbox-style-light');
searchAutofill.classList.add('searchbox-style-dark');
break;
};
}
};

function defaultSearchbarPosition(value) {
const searchbar = document.getElementById('searchbar');
const autofillContainer = document.getElementById('autofillContainer');
const wrap = document.getElementById('wrap');
sessionStorage.setItem('searchbar-position-drop', value);

switch (value) {
case 'top': {
searchbar.style.order = '0';
autofillContainer.style.order = '1';
autofillContainer.style.bottom = '0em';
autofillContainer.style.top = '3em';
wrap.style.margin = '0 auto auto auto';
break;
};
case 'bottom': {
searchbar.style.order = '1';
autofillContainer.style.order = '0';
autofillContainer.style.bottom = '2em';
autofillContainer.style.top = '';
wrap.style.margin = 'auto auto 0 auto';
break;
};
case 'middle': {
searchbar.style.order = '0';
autofillContainer.style.order = '1';
autofillContainer.style.bottom = '0em';
autofillContainer.style.top = '3em';
wrap.style.margin = 'auto auto auto auto';
break;
};
Expand Down
127 changes: 85 additions & 42 deletions js_modules/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { isUrlValid } from './validators.js';
import { Notify } from './utils/notifyDialog.js';

const MSG = 'You must enter a search query to continue.';
const container = document.querySelector('.autofillContainer');
const searchBG = document.querySelector('#searchBarFocusMode');

function loadSearchDomain(input) {
let domain = localStorage.getItem('default-search-url');
Expand Down Expand Up @@ -88,62 +90,103 @@ export function ebooks() {
}
};

export function switchToCLI(event) {
sessionStorage.setItem('input', event.target.value);
export function processSearchboxInput(event) {
const input = event.target.value;
sessionStorage.setItem('input', input);
switchToCLI(input);
showAutofillBox(input);
const autofillItems = document.querySelectorAll('.autofillItem');
if (autofillItems.length) {
const calc = 2.8 * autofillItems.length + 1;
searchBG.style.display = 'block';
setTimeout(() => {
// container.style.opacity = '1';
container.style.height = `${calc}em`;
container.style.paddingBlock = '0.5em';
searchBG.style.opacity = '1';
}, 1);
} else hideSearchBG();
};

const switchToCLI = (input) => {
const btnIcon = document.getElementById('search-btn-icon');
const placeholder = document
.querySelector('.searchTermPlaceholder');
const placeholderItem = document
.querySelector('.searchTermPlaceholderItem');
const currentIcon = localStorage.getItem('default-search-icon');
if (cliCheck(event.target.value)) {
if (cliCheck(input)) {
btnIcon.className = 'fa fa-terminal';
} else {
btnIcon.className = currentIcon;
};
const autocompleteDatabase =
JSON.parse(localStorage.getItem('autocompleteDatabase'));
if (!autocompleteDatabase) {
localStorage.setItem('autocompleteDatabase', SAMPLE_AUTOFILL);
}
const filter = autocompleteDatabase.filter((e) => {
return e.startsWith(event.target.value);
};

export const hideSearchBG = () => {
// getSearchTerm().blur();
searchBG.style.opacity = '0';
// container.style.opacity = '0';
container.style.paddingBlock = '0em';
container.style.height = '0em';
setTimeout(() => {
searchBG.style.display = 'none';
}, 200);
};

const showAutofillBox = (input) => {
input = input.toLowerCase();
const db = JSON.parse(localStorage.getItem('autocompleteDatabase'));
if (!db) localStorage.setItem('autocompleteDatabase', SAMPLE_AUTOFILL);

const filteredArray = db.filter((e) => {
if (e == input) return;
else return e.toLowerCase().startsWith(input);
});
if (filter[0]) {
placeholderItem.innerHTML = filter[0];
placeholder.style.height = '3em';
} else {
placeholderItem.innerHTML = '';
placeholder.style.height = '0em';
}

if (!event.target.value) {
placeholderItem.innerHTML = '';
placeholder.style.height = '0em';
}
console.log(filter[0]);
function autofill(event) {
getSearchTerm().value = event.target.innerHTML;
const e = new InputEvent('input');
getSearchTerm().dispatchEvent(e);
getSearchTerm().focus();
};

const generateSuggestions = (filteredArray) => {
clearSuggestions();
if (!input) return;
const theme = sessionStorage.getItem('searchbar-color-theme-drop');
let sortOrder = sessionStorage.getItem('searchbar-position-drop');
if (sortOrder == 'bottom') sortOrder = 'afterbegin';
else sortOrder = 'beforeend';
let i = 0;
for (const e of filteredArray) {
if (i == 5) return;
container.insertAdjacentHTML(sortOrder, `
<span
class="autofillItem disable-select searchbox-style-${theme}"
tabindex="1">${e}</span>
`);
i++;
}
};

const clearSuggestions = () => {
container.innerHTML = '';
};

generateSuggestions(filteredArray);
const items = document.querySelectorAll('.autofillItem');
items.forEach((e) => {
e.addEventListener('click', autofill);
e.addEventListener('focus', autofill);
});
};

export function enterToSearch(event) {
if (event.key == 'Enter') {
webSearch();
document.querySelector('#search-btn').click();
}
};

export function autofill() {
const placeholderItem = document
.querySelector('.searchTermPlaceholderItem');
getSearchTerm().value = placeholderItem.innerHTML;
};

const updateAutocompleteDatabase = (entry) => {
const autocompleteDatabase =
JSON.parse(localStorage.getItem('autocompleteDatabase'));
const set = new Set(autocompleteDatabase);

set.add(entry);
const updatedDatabase = Array.from(set);
localStorage
.setItem('autocompleteDatabase', JSON.stringify(updatedDatabase));
// console.log(x, entry);
const db = JSON.parse(localStorage.getItem('autocompleteDatabase'));
const set = new Set(db);
set.add(entry.toLowerCase());
const update = Array.from(set);
localStorage.setItem('autocompleteDatabase', JSON.stringify(update));
};
Loading

0 comments on commit 10a9ced

Please sign in to comment.