tilde/index.html
2018-12-15 12:45:02 -08:00

1060 lines
27 KiB
HTML

<!doctype html>
<script>
const CONFIG = {
// the category, name, key, url, search path and color for your commands
// if none of the specified keys are matched, the '*' key is used
commands: [
[null, 'Google', '*', 'https://encrypted.google.com', '/search?q={}', '#111'],
['Work', 'Drive', 'd', 'https://drive.google.com', '/drive/search?q={}', '#4285f4'],
['Work', 'GitHub', 'g', 'https://github.com', '/search?q={}', '#333'],
['Work', 'Keep', 'k', 'https://keep.google.com', '/#search/text={}', '#fb0'],
['Lurk', 'Hunt', 'H', 'https://www.producthunt.com', '/search?q={}', '#da552f'],
['Lurk', 'Reddit', 'r', 'https://www.reddit.com', '/search?q={}', '#5f99cf'],
['Lurk', 'Unsplash', 'u', 'https://unsplash.com/new', '/search/{}', '#000'],
['Listen', 'Hypem', 'h', 'https://hypem.com/popular', '/search/{}', '#83c441'],
['Listen', 'Line Radio', 'l', 'https://linerad.io', '/#{}', '#a29bfe'],
['Listen', 'SoundCloud', 's', 'https://soundcloud.com/discover', '/search?q={}', '#ff8800'],
['Watch', 'Netflix', 'n', 'https://www.netflix.com/browse', '/search?q={}', '#e50914'],
['Watch', 'Twitch', 't', 'https://www.twitch.tv/directory/following', null, '#6441a5'],
['Watch', 'YouTube', 'y', 'https://youtube.com/feed/subscriptions', '/results?search_query={}', '#cd201f'],
['Learn', 'Academy', 'a', 'https://www.khanacademy.org', '/search?page_search_query={}', '#9cb443'],
['Learn', 'Coursera', 'c', 'https://www.coursera.org', '/courses?query={}', '#407ED7'],
['Learn', 'Egghead', 'e', 'https://egghead.io', '/search?q={}', '#171C23'],
['Download', '7digital', '7', 'https://us.7digital.com', '/search?q={}', '#07606e'],
['Download', 'RARBG', 'R', 'https://rarbg.to/torrents.php', '/torrents.php?search={}', '#00d1b2'],
['Download', 'YTS', 'Y', 'https://yts.am/browse-movies/all/1080p/all/7/latest', '/browse-movies/{}', '#2f2f2f'],
],
// give suggestions as you type
suggestions: true,
// max amount of suggestions that will ever be displayed
suggestionsLimit: 4,
// the order and limit for each suggestion influencer
// "Default" suggestions come from CONFIG.defaultSuggestions
// "DuckDuckGo" suggestions come from the duck duck go search api
// "History" suggestions come from your previously entered queries
influencers: [
{ name: 'Default', limit: 4 },
{ name: 'History', limit: 1 },
{ name: 'DuckDuckGo', limit: 4 },
],
// default search suggestions for the specified queries
defaultSuggestions: {
'g': ['g/issues', 'g/pulls', 'gist.github.com'],
'l': ['l/#electronic+chill', 'l/#synthwave+chillwave', 'l/#focus+instrumental', 'l/#piano+sleep'],
'r': ['r/r/unixporn', 'r/r/startpages', 'r/r/webdev', 'r/r/technology'],
's': ['s/you/likes', 's/discover/the-upload'],
},
// instantly redirect when a key is matched
// put a space before any other queries to prevent unwanted redirects
instantRedirect: false,
// open queries in a new tab
newTab: true,
// dynamic background colors when command domains are matched
colors: true,
// specify a theme file
// remove or set to false to use the hardcoded theme
theme: false,
// the delimiter between the key and your search query
// e.g. to search GitHub for potatoes you'd type "g:potatoes"
searchDelimiter: ':',
// the delimiter between the key and a path
// e.g. type "r/r/unixporn" to go to "reddit.com/r/unixporn"
pathDelimiter: '/',
// the delimiter between the hours and minutes in the clock
clockDelimiter: ' ',
// change clock to twelve hour format
twelveHour: false,
};
</script>
<meta charset="utf-8">
<meta http-equiv="x-dns-prefetch-control" content="on">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex">
<title>~</title>
<style type="text/css">
@import url('https://fonts.googleapis.com/css?family=Lato:400,900');
:root {
--color0: #fff;
--color15: #33333f;
}
body {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
transition: background-color .2s;
background-color: var(--color0);
font-family: Lato, sans-serif;
color: var(--color15);
}
input,
button,
input:focus,
button:focus {
display: block;
box-sizing: border-box;
width: 100%;
margin: 0;
border: 0;
outline: 0;
background-color: transparent;
color: inherit;
font-family: Lato, sans-serif;
text-align: center;
-webkit-appearance: none;
-moz-appearance: none;
}
ul,
li {
margin: 0;
padding: 0;
list-style: none;
}
a,
a:focus {
color: inherit;
outline: 0;
}
#clock {
display: block;
margin-top: -.06em;
font-size: 6rem;
text-align: center;
letter-spacing: .05em;
cursor: pointer;
}
#am-pm {
font-size: .5em;
}
#search-form {
padding: 1em;
background-color: var(--color15);
transition: background-color .5s;
color: var(--color0);
box-sizing: border-box;
z-index: 2;
}
#search-form > div {
width: 100%;
}
#search-input,
#search-input:focus {
width: 100%;
margin-bottom: 20px;
font-size: 1.5em;
font-weight: 900;
letter-spacing: .05em;
text-transform: uppercase;
}
#search-suggestions {
display: none;
flex-wrap: wrap;
justify-content: center;
}
body.suggestions #search-suggestions {
display: flex;
}
.search-suggestion {
padding: .7em 1em;
white-space: nowrap;
font-size: 1.1em;
cursor: pointer;
}
.search-suggestion.highlight {
background-color: var(--color0);
color: var(--color15);
}
.search-suggestion b {
position: relative;
font-weight: 400;
}
.search-suggestion b::after {
content: ' ';
position: absolute;
right: 0;
bottom: -.4em;
left: 0;
height: 3px;
background-color: var(--color0);
opacity: .3;
}
.search-suggestion.highlight b::after {
opacity: 0;
}
#help {
display: block;
padding: 8vw;
background-color: var(--color0);
font-size: 1.3rem;
z-index: 1;
}
.category {
margin-bottom: 2rem;
}
.category:last-of-type {
margin-bottom: 0;
}
.category-name {
margin: 0 0 2rem;
font-size: .7em;
letter-spacing: .2em;
text-transform: uppercase;
}
.command a {
display: block;
position: relative;
margin: 1em 0;
font-size: .9em;
line-height: 2em;
text-decoration: none;
}
.command:last-of-type a {
margin-bottom: 0;
}
.command-key {
display: block;
float: left;
width: 2.5em;
margin-right: 1em;
border-radius: 50%;
background-color: var(--color15);
color: var(--color0);
font-size: .8em;
text-align: center;
}
.command-name {
position: relative;
overflow: hidden;
}
.command-name::after {
content: ' ';
position: absolute;
right: 0;
bottom: -.35em;
left: 0;
height: 2px;
transition: .2s;
transform: translateX(-2em);
background: var(--color15);
opacity: 0;
}
.command a:hover .command-name::after,
.command a:focus .command-name::after {
transform: translateX(0);
opacity: 1;
}
.overlay {
position: fixed;
top: 0;
left: 0;
overflow: auto;
box-sizing: border-box;
width: 100%;
height: 100%;
visibility: hidden;
}
body.help #help.overlay,
body.form #search-form.overlay {
visibility: visible;
}
.center {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
box-sizing: border-box;
}
@media (min-width: 500px) {
.categories {
display: grid;
grid-template-columns: 250px 185px;
justify-content: space-around;
}
.category:nth-last-child(2) {
margin-bottom: 0;
}
#search-input,
#search-input:focus {
font-size: 3em;
}
}
@media (min-width: 1000px) {
#help {
display: flex;
padding: 0;
}
.category {
margin: 2rem 0;
}
.categories {
grid-template-columns: repeat(2, 300px) 185px;
}
}
@media (min-width: 1700px) {
.categories {
grid-template-columns: repeat(5, 250px) 185px;
}
}
</style>
<div class="center">
<time id="clock"></time>
</div>
<form class="overlay center" id="search-form" autocomplete="off" spellcheck="false">
<div>
<input id="search-input" type="text" title="search">
<ul id="search-suggestions"></ul>
</div>
</form>
<aside class="overlay center" id="help"></aside>
<script>
const $ = {
bodyClassAdd: c => $.el('body').classList.add(c),
bodyClassRemove: c => $.el('body').classList.remove(c),
el: s => document.querySelector(s),
els: s => [].slice.call(document.querySelectorAll(s) || []),
escapeRegex: s => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),
ieq: (a, b) => a.toLowerCase() === b.toLowerCase(),
iin: (a, b) => a.toLowerCase().indexOf(b.toLowerCase()) !== -1,
isDown: e => ['c-n', 'down', 'tab'].includes($.key(e)),
isRemove: e => ['backspace', 'delete'].includes($.key(e)),
isUp: e => ['c-p', 'up', 's-tab'].includes($.key(e)),
jsonp: url => {
let script = document.createElement('script');
script.src = url;
$.el('head').appendChild(script);
},
key: e => {
const ctrl = e.ctrlKey;
const shift = e.shiftKey;
switch (e.which) {
case 8: return 'backspace';
case 9: return shift ? 's-tab' : 'tab';
case 13: return 'enter';
case 16: return 'shift';
case 17: return 'ctrl';
case 18: return 'alt';
case 27: return 'escape';
case 38: return 'up';
case 40: return 'down';
case 46: return 'delete';
case 78: return ctrl ? 'c-n' : 'n';
case 80: return ctrl ? 'c-p' : 'n';
case 91: return 'super';
}
},
pad: v => ('0' + v.toString()).slice(-2),
};
class Clock {
constructor(options) {
this._el = $.el('#clock');
this._delimiter = options.delimiter;
this._form = options.form;
this._twelveHour = options.twelveHour;
this._setTime = this._setTime.bind(this);
this._el.addEventListener('click', this._form.show);
this._start();
}
_setTime() {
const date = new Date();
let hours = $.pad(date.getHours());
let amPm = '';
if (this._twelveHour) {
hours = date.getHours() > 12
? date.getHours() - 12
: date.getHours() === 0
? 12
: date.getHours();
amPm = `&nbsp;<span id="am-pm">` +
`${date.getHours() > 12 ? 'PM' : 'AM'}</span>`;
}
const minutes = $.pad(date.getMinutes());
this._el.innerHTML = `${hours}${this._delimiter}${minutes}${amPm}`;
this._el.setAttribute('datetime', date.toTimeString());
}
_start() {
this._setTime();
setInterval(this._setTime, 1000);
}
}
class Help {
constructor(options) {
this._el = $.el('#help');
this._commands = options.commands;
this._newTab = options.newTab;
this._toggled = false;
this._handleKeydown = this._handleKeydown.bind(this);
this._buildAndAppendLists();
this._registerEvents();
}
toggle(show) {
this._toggled = (typeof show !== 'undefined') ? show : !this._toggled;
this._toggled ? $.bodyClassAdd('help') : $.bodyClassRemove('help');
}
_buildAndAppendLists() {
const lists = document.createElement('ul');
lists.classList.add('categories');
this._getCategories().forEach(category => {
lists.insertAdjacentHTML(
'beforeend',
`<li class="category">
<h2 class="category-name">${category}</h2>
<ul>${this._buildListCommands(category)}</ul>
</li>`,
);
});
this._el.appendChild(lists);
}
_buildListCommands(category) {
return this._commands
.map(([cmdCategory, name, key, url]) => {
if (cmdCategory === category) {
return (
`<li class="command">
<a href="${url}" target="${this._newTab ? '_blank' : '_self'}">
<span class="command-key">${key}</span>
<span class="command-name">${name}</span>
</a>
</li>`
);
}
})
.join('');
}
_getCategories() {
const categories = this._commands
.map(([category]) => category)
.filter(category => category);
return [...new Set(categories)];
}
_handleKeydown(e) {
if ($.key(e) === 'escape') this.toggle(false);
}
_registerEvents() {
document.addEventListener('keydown', this._handleKeydown);
}
}
class Influencer {
constructor(options) {
this._limit = options.limit;
this._queryParser = options.queryParser;
}
addItem() {}
getSuggestions() {}
_addSearchPrefix(items, query) {
const searchPrefix = this._getSearchPrefix(query);
return items.map(s => searchPrefix ? searchPrefix + s : s);
}
_getSearchPrefix(query) {
const { isSearch, key, split } = this._parseQuery(query);
return isSearch ? `${key}${split} ` : false;
}
_parseQuery(query) {
return this._queryParser.parse(query);
}
}
class DefaultInfluencer extends Influencer {
constructor({ defaultSuggestions }) {
super(...arguments);
this._defaultSuggestions = defaultSuggestions;
}
getSuggestions(query) {
return new Promise(resolve => {
const suggestions = this._defaultSuggestions[query];
resolve(suggestions ? suggestions.slice(0, this._limit) : []);
});
}
}
class DuckDuckGoInfluencer extends Influencer {
constructor({ queryParser }) {
super(...arguments);
}
getSuggestions(rawQuery) {
const { query } = this._parseQuery(rawQuery);
if (!query) return Promise.resolve([]);
return new Promise(resolve => {
const endpoint = 'https://duckduckgo.com/ac/';
const callback = 'autocompleteCallback';
window[callback] = res => {
const suggestions = res.map(i => i.phrase)
.filter(s => !$.ieq(s, query))
.slice(0, this._limit);
resolve(this._addSearchPrefix(suggestions, rawQuery));
};
$.jsonp(`${endpoint}?callback=${callback}&q=${query}`);
});
}
}
class HistoryInfluencer extends Influencer {
constructor() {
super(...arguments);
this._storeName = 'history';
}
addItem(query) {
if (query.length < 2) return;
let exists;
const history = this._getHistory().map(([item, count]) => {
const match = $.ieq(item, query);
if (match) exists = true;
return [item, match ? count + 1 : count];
});
if (!exists) history.push([query, 1]);
const sorted = history
.sort((current, next) => current[1] - next[1])
.reverse();
this._setHistory(sorted);
}
getSuggestions(query) {
return new Promise(resolve => {
const suggestions = this._getHistory()
.map(([item]) => item)
.filter(item => query && !$.ieq(item, query) && $.iin(item, query))
.slice(0, this._limit);
resolve(suggestions);
});
}
_fetch() {
return JSON.parse(localStorage.getItem(this._storeName)) || [];
}
_getHistory() {
this._history = this._history || this._fetch();
return this._history;
}
_save(history) {
localStorage.setItem(this._storeName, JSON.stringify(history));
}
_setHistory(history) {
this._history = history;
this._save(history);
}
}
class Suggester {
constructor(options) {
this._el = $.el('#search-suggestions');
this._influencers = options.influencers;
this._limit = options.limit;
this._suggestionEls = [];
this._handleKeydown = this._handleKeydown.bind(this);
this._registerEvents();
}
setOnClick(callback) {
this._onClick = callback;
}
setOnHighlight(callback) {
this._onHighlight = callback;
}
setOnUnhighlight(callback) {
this._onUnhighlight = callback;
}
success(query) {
this._clearSuggestions();
this._influencers.forEach(i => i.addItem(query));
}
suggest(input) {
input = input.trim();
if (input === '') this._clearSuggestions();
Promise.all(this._getInfluencerPromises(input)).then(res => {
const suggestions = Suggester._flattenAndUnique(res);
this._clearSuggestions();
if (suggestions.length) {
this._appendSuggestions(suggestions, input);
this._registerSuggestionEvents();
$.bodyClassAdd('suggestions');
}
});
}
// [[1, 2], [1, 2, 3, 4]] -> [1, 2, 3, 4]
static _flattenAndUnique(array) {
return [...new Set([].concat.apply([], array))];
}
_appendSuggestions(suggestions, input) {
for (const [i, suggestion] of suggestions.entries()) {
const match = new RegExp($.escapeRegex(input), 'ig');
const suggestionHtml = suggestion.replace(match, `<b>${input}</b>`);
this._el.insertAdjacentHTML(
'beforeend',
`<li>
<button
type="button"
class="js-search-suggestion search-suggestion"
data-suggestion="${suggestion}"
tabindex="-1"
>
${suggestionHtml}
</button>
</li>`,
);
if (i + 1 >= this._limit) break;
}
this._suggestionEls = $.els('.js-search-suggestion');
}
_clearClickEvents() {
this._suggestionEls.forEach(el => {
const callback = this._onClick.bind(null, el.value);
el.removeEventListener('click', callback);
});
}
_clearSuggestions() {
$.bodyClassRemove('suggestions');
this._clearClickEvents();
this._suggestionEls = [];
this._el.innerHTML = '';
}
_focusNext(e) {
const exists = this._suggestionEls.some((el, i) => {
if (el.classList.contains('highlight')) {
this._highlight(this._suggestionEls[i + 1], e);
return true;
}
});
if (!exists) this._highlight(this._suggestionEls[0], e);
}
_focusPrevious(e) {
const exists = this._suggestionEls.some((el, i) => {
if (el.classList.contains('highlight') && i) {
this._highlight(this._suggestionEls[i - 1], e);
return true;
}
});
if (!exists) this._unHighlight(e);
}
_getInfluencerPromises(input) {
return this._influencers
.map(influencer => influencer.getSuggestions(input));
}
_handleKeydown(e) {
if ($.isDown(e)) this._focusNext(e);
if ($.isUp(e)) this._focusPrevious(e);
}
_highlight(el, e) {
this._unHighlight();
if (el) {
this._onHighlight(el.getAttribute('data-suggestion'));
el.classList.add('highlight');
e.preventDefault();
}
}
_registerEvents() {
document.addEventListener('keydown', this._handleKeydown);
}
_registerSuggestionEvents() {
const noHighlightUntilMouseMove = () => {
window.removeEventListener('mousemove', noHighlightUntilMouseMove);
this._suggestionEls.forEach(el => {
const value = el.getAttribute('data-suggestion');
el.addEventListener('mouseover', this._highlight.bind(this, el));
el.addEventListener('mouseout', this._unHighlight.bind(this));
el.addEventListener('click', this._onClick.bind(null, value));
});
};
window.addEventListener('mousemove', noHighlightUntilMouseMove);
}
_unHighlight(e) {
const el = $.el('.highlight');
if (el) {
this._onUnhighlight();
el.classList.remove('highlight');
if (e) e.preventDefault();
}
}
}
class QueryParser {
constructor(options) {
this._commands = options.commands;
this._searchDelimiter = options.searchDelimiter;
this._pathDelimiter = options.pathDelimiter;
this._protocolRegex = /^[a-zA-Z]+:\/\//i;
this._urlRegex = /^((https?:\/\/)?[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?)$/i;
}
parse(query) {
const res = { query: query, split: null };
if (query.match(this._urlRegex)) {
const hasProtocol = query.match(this._protocolRegex);
res.redirect = hasProtocol ? query : 'http://' + query;
} else {
const splitSearch = query.split(this._searchDelimiter);
const splitPath = query.split(this._pathDelimiter);
this._commands.some(([category, name, key, url, searchPath]) => {
res.isKey = query === key;
res.isSearch = !res.isKey && splitSearch[0] === key;
res.isPath = !res.isKey && splitPath[0] === key;
if (res.isKey || res.isSearch || res.isPath) {
res.key = key;
if (res.isSearch && searchPath) {
res.split = this._searchDelimiter;
res.query = QueryParser._shiftAndTrim(splitSearch, res.split);
res.redirect = QueryParser._prepSearch(url, searchPath, res.query);
} else if (res.isPath) {
res.split = this._pathDelimiter;
res.path = QueryParser._shiftAndTrim(splitPath, res.split);
res.redirect = QueryParser._prepPath(url, res.path);
} else {
res.redirect = url;
}
return true;
}
if (key === '*') {
res.redirect = QueryParser._prepSearch(url, searchPath, query);
}
});
}
res.color = QueryParser._getColorFromUrl(this._commands, res.redirect);
return res;
}
static _getColorFromUrl(commands, url) {
const domain = new URL(url).hostname;
return commands
.filter(c => new URL(c[3]).hostname === domain)
.map(c => c[5])[0] || null;
}
static _prepPath(url, path) {
return QueryParser._stripUrlPath(url) + '/' + path;
}
static _prepSearch(url, searchPath, query) {
if (!searchPath) return url;
const baseUrl = QueryParser._stripUrlPath(url);
const urlQuery = encodeURIComponent(query);
searchPath = searchPath.replace('{}', urlQuery);
return baseUrl + searchPath;
}
static _shiftAndTrim(arr, delimiter) {
arr.shift();
return arr.join(delimiter).trim();
}
static _stripUrlPath(url) {
const parser = document.createElement('a');
parser.href = url;
return `${parser.protocol}//${parser.hostname}`;
}
}
class Form {
constructor(options) {
this._formEl = $.el('#search-form');
this._inputEl = $.el('#search-input');
this._colors = options.colors;
this._help = options.help;
this._suggester = options.suggester;
this._queryParser = options.queryParser;
this._instantRedirect = options.instantRedirect;
this._newTab = options.newTab;
this._inputElVal = '';
this.show = this.show.bind(this);
this._clearPreview = this._clearPreview.bind(this);
this._handleInput = this._handleInput.bind(this);
this._handleKeydown = this._handleKeydown.bind(this);
this._previewValue = this._previewValue.bind(this);
this._submitForm = this._submitForm.bind(this);
this._submitWithValue = this._submitWithValue.bind(this);
this._registerEvents();
this._loadQueryParam();
}
hide() {
$.bodyClassRemove('form');
this._inputEl.value = '';
this._inputElVal = '';
}
show() {
$.bodyClassAdd('form');
this._inputEl.focus();
}
_clearPreview() {
this._previewValue(this._inputElVal);
this._inputEl.focus();
}
_handleKeydown(e) {
if ($.isUp(e) || $.isDown(e) || $.isRemove(e)) return;
switch ($.key(e)) {
case 'alt':
case 'ctrl':
case 'enter':
case 'shift':
case 'super':
return;
case 'escape':
this.hide();
return;
}
this.show();
}
_handleInput() {
const newQuery = this._inputEl.value;
const isHelp = newQuery === '?';
const { isKey } = this._queryParser.parse(newQuery);
this._inputElVal = newQuery;
this._setBackgroundFromQuery(newQuery);
if (!newQuery || isHelp) this.hide();
if (isHelp) this._help.toggle();
if (this._instantRedirect && isKey) this._submitWithValue(newQuery);
if (this._suggester) this._suggester.suggest(newQuery);
}
_loadQueryParam() {
const q = new URLSearchParams(window.location.search).get('q');
if (q) this._submitWithValue(q);
}
_previewValue(value) {
this._inputEl.value = value;
this._setBackgroundFromQuery(value);
}
_redirect(redirect) {
if (this._newTab) window.open(redirect, '_blank');
else window.location.href = redirect;
}
_registerEvents() {
document.addEventListener('keydown', this._handleKeydown);
this._inputEl.addEventListener('input', this._handleInput);
this._formEl.addEventListener('submit', this._submitForm, false);
if (this._suggester) {
this._suggester.setOnClick(this._submitWithValue);
this._suggester.setOnHighlight(this._previewValue);
this._suggester.setOnUnhighlight(this._clearPreview);
}
}
_setBackgroundFromQuery(query) {
if (!this._colors) return;
const { color } = this._queryParser.parse(query);
this._formEl.style.backgroundColor = color;
}
_submitForm(e) {
if (e) e.preventDefault();
const query = this._inputEl.value;
if (this._suggester) this._suggester.success(query);
this.hide();
this._redirect(this._queryParser.parse(query).redirect);
}
_submitWithValue(value) {
this._inputEl.value = value;
this._submitForm();
}
}
</script>
<script>
const getHelp = () => {
return new Help({
commands: CONFIG.commands,
newTab: CONFIG.newTab,
});
};
const getInfluencers = () => {
const availableInfluencers = {
Default: DefaultInfluencer,
DuckDuckGo: DuckDuckGoInfluencer,
History: HistoryInfluencer,
};
return CONFIG.influencers.map(i => {
return new availableInfluencers[i.name]({
limit: i.limit,
queryParser: getQueryParser(),
defaultSuggestions: CONFIG.defaultSuggestions,
});
});
};
const getSuggester = () => {
return new Suggester({
influencers: getInfluencers(),
limit: CONFIG.suggestionsLimit,
});
};
const getQueryParser = () => {
return new QueryParser({
commands: CONFIG.commands,
pathDelimiter: CONFIG.pathDelimiter,
searchDelimiter: CONFIG.searchDelimiter,
});
};
const getForm = () => {
return new Form({
colors: CONFIG.colors,
help: getHelp(),
instantRedirect: CONFIG.instantRedirect,
newTab: CONFIG.newTab,
queryParser: getQueryParser(),
suggester: CONFIG.suggestions ? getSuggester() : false,
});
};
new Clock({
twelveHour: CONFIG.twelveHour,
delimiter: CONFIG.clockDelimiter,
form: getForm(),
});
if (CONFIG.theme) {
const link = document.createElement('link');
link.href = CONFIG.theme;
link.type = 'text/css';
link.rel = 'stylesheet';
$.el('head').appendChild(link);
}
</script>