initial redesign

This commit is contained in:
Cade Scroggins
2017-07-16 20:02:46 -07:00
parent ffa5abaf76
commit 41e7bc5003
+157 -107
View File
@@ -3,8 +3,11 @@
<script> <script>
const CONFIG = { const CONFIG = {
// the key, name, redirect url and search path for your commands // the key, name, url and search path for your commands
// if none of the specified keys are matched, the '*' key is used
// if the key is set to null, the command is disabled
commands: [ commands: [
['*', 'Google', 'https://encrypted.google.com', '/search?q={}'],
['7', '7digital', 'https://us.7digital.com', '/search?q={}'], ['7', '7digital', 'https://us.7digital.com', '/search?q={}'],
['g', 'GitHub', 'https://github.com', '/search?q={}'], ['g', 'GitHub', 'https://github.com', '/search?q={}'],
['h', 'Hypem', 'http://hypem.com/popular', '/search/{}'], ['h', 'Hypem', 'http://hypem.com/popular', '/search/{}'],
@@ -37,9 +40,6 @@
'Download': ['7digital', 'TPB', 'YIFY'], 'Download': ['7digital', 'TPB', 'YIFY'],
}, },
// if none of the specified keys are matched, this is used for searching
defaultSearch: 'https://encrypted.google.com/search?q={}',
// the delimiter between the key and your search query // the delimiter between the key and your search query
// e.g. to search GitHub for potatoes you'd type "g:potatoes" // e.g. to search GitHub for potatoes you'd type "g:potatoes"
searchDelimiter: ':', searchDelimiter: ':',
@@ -83,10 +83,7 @@
<title>~</title> <title>~</title>
<style type="text/css"> <style type="text/css">
@font-face { @import url('https://fonts.googleapis.com/css?family=Lato:400,900');
font-family: 'Lato';
src: url('https://fonts.gstatic.com/s/lato/v11/22JRxvfANxSmnAhzbFH8PgLUuEpTyoUstqEm5AMlJo4.woff2') format('woff2');
}
body { body {
position: absolute; position: absolute;
@@ -96,27 +93,9 @@
height: 100%; height: 100%;
margin: 0; margin: 0;
padding: 0; padding: 0;
transition: background .2s;
font-family: Lato, sans-serif;
color: #222; color: #222;
font-family: 'Lato', sans-serif;
}
main {
position: absolute;
top: 50%;
right: 0;
left: 0;
width: 90%;
max-width: 310px;
margin: 0 auto;
transform: translateY(-100px);
text-align: center;
}
time {
display: block;
margin-bottom: 20px;
font-size: 5rem;
letter-spacing: 6px;
} }
input, input,
@@ -126,11 +105,13 @@
display: block; display: block;
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
margin: 0;
border: 0; border: 0;
outline: 0; outline: 0;
background: transparent; background: transparent;
color: #fff; color: #fff;
font-family: 'Lato', sans-serif; font-family: Lato, sans-serif;
text-align: center;
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
} }
@@ -142,77 +123,75 @@
list-style: none; list-style: none;
} }
#search-input, a {
#search-input:focus { color: inherit;
padding: 12px;
border-radius: 2px;
background: #222;
font-size: 1.1rem;
} }
body.suggestions #search-input { #clock {
border-radius: 2px 2px 0 0; display: block;
font-size: 6rem;
letter-spacing: .05em;
}
#search-form {
background: #111;
z-index: 2;
}
#search-input,
#search-input:focus {
margin-bottom: 20px;
font-size: 3em;
font-weight: 900;
letter-spacing: .05em;
text-transform: uppercase;
} }
#search-suggestions { #search-suggestions {
display: none; display: none;
padding: 4px 0; justify-content: center;
border-radius: 0 0 2px 2px;
background: #111;
overflow: hidden; overflow: hidden;
} }
body.suggestions #search-suggestions { body.suggestions #search-suggestions {
display: block; display: flex;
} }
.search-suggestion { .search-suggestion {
margin: -4px 0; padding: 1em;
padding: 10px 12px; white-space: nowrap;
transition: background .2s; font-size: 1.1em;
font-size: .8rem;
text-align: left;
cursor: pointer; cursor: pointer;
} }
.search-suggestion:focus, .search-suggestion:focus,
.search-suggestion.highlight { .search-suggestion.highlight {
background: #333; background-color: #fff;
color: #222;
}
.search-suggestion b {
font-weight: 400;
text-decoration: line-through;
} }
#help { #help {
position: fixed;
top: 0;
left: 0;
visibility: hidden;
overflow: auto;
box-sizing: border-box;
width: 100%;
height: 100%;
padding: 8vw; padding: 8vw;
transition: visibility .2s, opacity .2s, transform .4s; background: #fff;
transform: translateY(10px); font-size: 1.3rem;
opacity: 0; z-index: 1;
background: #606c88;
background: -webkit-linear-gradient(to right, #3f4c6b, #606c88);
background: linear-gradient(to right, #3f4c6b, #606c88);
font-size: 1.2rem;
}
body.help #help {
visibility: visible;
transform: translateY(0);
opacity: 1;
} }
.category { .category {
width: 100%;
margin-bottom: 3em; margin-bottom: 3em;
} }
.category:last-of-type {
margin-bottom: 0;
}
.category-name { .category-name {
margin: 0 0 2em; margin: 0 0 2em;
color: rgba(255, 255, 255, .6);
font-size: .7em; font-size: .7em;
letter-spacing: .2em; letter-spacing: .2em;
text-transform: uppercase; text-transform: uppercase;
@@ -222,8 +201,7 @@
display: block; display: block;
position: relative; position: relative;
padding: .5em 0; padding: .5em 0;
color: #fff; font-size: .9em;
font-size: 1em;
line-height: 2em; line-height: 2em;
text-decoration: none; text-decoration: none;
} }
@@ -234,7 +212,8 @@
width: 2.5em; width: 2.5em;
margin-right: 1em; margin-right: 1em;
border-radius: 50%; border-radius: 50%;
background-color: rgba(255, 255, 255, .1); background-color: #222;
color: #fff;
font-size: .8em; font-size: .8em;
text-align: center; text-align: center;
} }
@@ -253,7 +232,7 @@
height: 2px; height: 2px;
transition: .2s; transition: .2s;
transform: translateX(-2em); transform: translateX(-2em);
background-color: rgba(255, 255, 255, .2); background-color: #222;
opacity: 0; opacity: 0;
} }
@@ -262,37 +241,71 @@
opacity: 1; opacity: 1;
} }
@media (min-width: 1000px) { .overlay {
position: fixed;
top: 0;
left: 0;
overflow: auto;
box-sizing: border-box;
width: 100%;
height: 100%;
transition: opacity .3s;
visibility: hidden;
opacity: 0;
}
body.help #help.overlay,
body.form #search-form.overlay {
visibility: visible;
opacity: 1;
}
.middle {
position: absolute;
top: 50%;
right: 0;
left: 0;
transform: translateY(-50%);
text-align: center;
}
@media (min-width: 1200px) {
#help { #help {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
padding: 2em; padding: 2em;
font-size: 1.3vw;
} }
#help>ul { #help>ul {
display: flex; display: flex;
justify-content: space-around; justify-content: center;
width: 100%; width: 100%;
} }
.category { .category {
width: 10em; min-width: 18vw;
margin-bottom: 0; margin-bottom: 0;
} }
.category:last-of-type {
min-width: 0;
}
} }
</style> </style>
<main> <div class="middle">
<time id="clock"></time> <time id="clock"></time>
<form id="search-form" autocomplete="off"> </div>
<input id="search-input" type="text" autofocus>
<ul id="search-suggestions"></ul>
</form>
</main>
<aside id="help"></aside> <form class="overlay" id="search-form" autocomplete="off" spellcheck="false">
<div class="middle">
<input id="search-input" type="text">
<ul id="search-suggestions"></ul>
</div>
</form>
<aside class="overlay" id="help"></aside>
<script> <script>
const $ = { const $ = {
@@ -319,12 +332,17 @@
case 8: return 'backspace'; case 8: return 'backspace';
case 9: return shift ? 's-tab' : 'tab'; case 9: return shift ? 's-tab' : 'tab';
case 13: return 'enter'; case 13: return 'enter';
case 16: return 'shift';
case 17: return 'ctrl';
case 18: return 'alt';
case 27: return 'escape'; case 27: return 'escape';
case 38: return 'up'; case 38: return 'up';
case 40: return 'down'; case 40: return 'down';
case 46: return 'delete'; case 46: return 'delete';
case 78: return ctrl ? 'c-n' : 'n'; case 78: return ctrl ? 'c-n' : 'n';
case 80: return ctrl ? 'c-p' : 'n'; case 80: return ctrl ? 'c-p' : 'n';
case 91: return 'super';
case 191: return '?';
} }
}, },
}; };
@@ -453,7 +471,11 @@
const callback = 'autocompleteCallback'; const callback = 'autocompleteCallback';
window[callback] = res => { window[callback] = res => {
resolve(res.slice(0, this._limit).map(i => i.phrase)); const suggestions = res.map(i => i.phrase)
.filter(suggestion => suggestion !== query)
.slice(0, this._limit);
resolve(suggestions);
}; };
$.jsonp(`${endpoint}?callback=${callback}&q=${query}`); $.jsonp(`${endpoint}?callback=${callback}&q=${query}`);
@@ -484,9 +506,9 @@
getSuggestions(query) { getSuggestions(query) {
return new Promise(resolve => { return new Promise(resolve => {
const suggestions = this._getHistory() const suggestions = this._getHistory()
.filter(([item]) => this._itemContainsQuery(query, item)) .map(([item]) => item)
.slice(0, this._limit) .filter(item => this._itemContainsQuery(query, item))
.map(([item]) => item); .slice(0, this._limit);
resolve(suggestions); resolve(suggestions);
}); });
@@ -502,7 +524,7 @@
} }
_itemContainsQuery(query, item) { _itemContainsQuery(query, item) {
return query && item.indexOf(query) !== -1; return query && query !== item && item.indexOf(query) !== -1;
} }
_save(history) { _save(history) {
@@ -552,9 +574,9 @@
Promise.all(this._getInfluencerPromises(input)).then(res => { Promise.all(this._getInfluencerPromises(input)).then(res => {
const suggestions = this._flattenAndUnique(res); const suggestions = this._flattenAndUnique(res);
this._clearSuggestions();
if (suggestions.length) { if (suggestions.length) {
this._clearSuggestions();
this._appendSuggestions(suggestions, input); this._appendSuggestions(suggestions, input);
this._registerSuggestionEvents(); this._registerSuggestionEvents();
$.bodyClassAdd('suggestions'); $.bodyClassAdd('suggestions');
@@ -677,9 +699,8 @@
} }
class QueryParser { class QueryParser {
constructor({ commands, defaultSearch, pathDelimiter, searchDelimiter }) { constructor({ commands, pathDelimiter, searchDelimiter }) {
this._commands = commands; this._commands = commands;
this._defaultSearch = defaultSearch;
this._searchDelimiter = searchDelimiter; this._searchDelimiter = searchDelimiter;
this._pathDelimiter = pathDelimiter; this._pathDelimiter = pathDelimiter;
this._protocolRegex = /^[a-zA-Z]+:\/\//i; this._protocolRegex = /^[a-zA-Z]+:\/\//i;
@@ -687,8 +708,7 @@
} }
generateRedirect(query) { generateRedirect(query) {
const encodedQuery = encodeURIComponent(query); let redirectUrl;
let redirectUrl = this._defaultSearch.replace('{}', encodedQuery);
if (query.match(this._urlRegex)) { if (query.match(this._urlRegex)) {
const hasProtocol = query.match(this._protocolRegex); const hasProtocol = query.match(this._protocolRegex);
@@ -712,6 +732,10 @@
return true; return true;
} }
if (key === '*') {
redirectUrl = this._prepSearch(url, searchPath, query);
}
}); });
} }
@@ -736,10 +760,13 @@
return this._stripUrlPath(url) + '/' + path; return this._stripUrlPath(url) + '/' + path;
} }
_prepSearch(url, searchPath, splitSearch) { _prepSearch(url, searchPath, query) {
if (!searchPath) return url; if (!searchPath) return url;
const baseUrl = this._stripUrlPath(url); const baseUrl = this._stripUrlPath(url);
const query = this._shiftAndTrim(splitSearch, this._searchDelimiter);
query = query.constructor !== Array ? query.trim()
: this._shiftAndTrim(query, this._searchDelimiter);
const urlQuery = encodeURIComponent(query); const urlQuery = encodeURIComponent(query);
searchPath = searchPath.replace('{}', urlQuery); searchPath = searchPath.replace('{}', urlQuery);
return baseUrl + searchPath; return baseUrl + searchPath;
@@ -773,6 +800,7 @@
_bindMethods() { _bindMethods() {
this._clearPreview = this._clearPreview.bind(this); this._clearPreview = this._clearPreview.bind(this);
this._handleKeydown = this._handleKeydown.bind(this);
this._handleKeypress = this._handleKeypress.bind(this); this._handleKeypress = this._handleKeypress.bind(this);
this._handleKeyup = this._handleKeyup.bind(this); this._handleKeyup = this._handleKeyup.bind(this);
this._previewValue = this._previewValue.bind(this); this._previewValue = this._previewValue.bind(this);
@@ -783,6 +811,7 @@
_clearInput() { _clearInput() {
this._inputEl.value = ''; this._inputEl.value = '';
this._inputElVal = ''; this._inputElVal = '';
$.bodyClassRemove('form');
} }
_clearPreview() { _clearPreview() {
@@ -790,14 +819,39 @@
this._inputEl.focus(); this._inputEl.focus();
} }
_handleKeydown(e) {
switch ($.key(e)) {
case 'alt':
case 'ctrl':
case 'enter':
case 'shift':
case 'super':
break;
case 'escape':
this._clearInput();
break;
case '?':
if (!this._inputElVal) {
e.preventDefault();
this._help.toggle();
break;
}
default:
if ($.isUp(e) || $.isDown(e)) break;
$.bodyClassAdd('form');
this._inputEl.focus();
}
}
_handleKeypress(e) { _handleKeypress(e) {
const newChar = String.fromCharCode(e.which); const newChar = String.fromCharCode(e.which);
const newQuery = this._inputEl.value + newChar; const newQuery = this._inputEl.value + newChar;
const validChar = newChar.length && $.key(e) !== 'enter'; const validChar = newChar.length && $.key(e) !== 'enter';
const queryDiffers = this._inputElVal !== newQuery; const queryDiffers = this._inputElVal !== newQuery;
if (validChar) this._help.toggle(false);
if ( if (
this._instantRedirect && this._instantRedirect &&
this._queryParser.instantRedirect(newQuery, this._submitWithValue) this._queryParser.instantRedirect(newQuery, this._submitWithValue)
@@ -811,6 +865,7 @@
_handleKeyup(e) { _handleKeyup(e) {
const newQuery = this._inputEl.value; const newQuery = this._inputEl.value;
if (!newQuery) $.bodyClassRemove('form');
if (this._suggester && $.isRemove(e) && this._inputElVal !== newQuery) { if (this._suggester && $.isRemove(e) && this._inputElVal !== newQuery) {
this._suggester.suggest(newQuery); this._suggester.suggest(newQuery);
@@ -828,6 +883,7 @@
} }
_registerEvents() { _registerEvents() {
document.addEventListener('keydown', this._handleKeydown);
this._inputEl.addEventListener('keypress', this._handleKeypress); this._inputEl.addEventListener('keypress', this._handleKeypress);
this._inputEl.addEventListener('keyup', this._handleKeyup); this._inputEl.addEventListener('keyup', this._handleKeyup);
this._formEl.addEventListener('submit', this._submitForm, false); this._formEl.addEventListener('submit', this._submitForm, false);
@@ -840,13 +896,8 @@
if (e) e.preventDefault(); if (e) e.preventDefault();
const query = this._inputEl.value.trim(); const query = this._inputEl.value.trim();
this._clearInput(); this._clearInput();
this._suggester.success(query);
if (!query || query === '?') { this._redirect(this._queryParser.generateRedirect(query));
this._help.toggle();
} else {
this._suggester.success(query);
this._redirect(this._queryParser.generateRedirect(query));
}
} }
_submitWithValue(value) { _submitWithValue(value) {
@@ -890,7 +941,6 @@
const getQueryParser = () => { const getQueryParser = () => {
return new QueryParser({ return new QueryParser({
commands: CONFIG.commands, commands: CONFIG.commands,
defaultSearch: CONFIG.defaultSearch,
pathDelimiter: CONFIG.pathDelimiter, pathDelimiter: CONFIG.pathDelimiter,
searchDelimiter: CONFIG.searchDelimiter, searchDelimiter: CONFIG.searchDelimiter,
}); });