diff --git a/src/config.json b/src/config.json new file mode 100644 index 0000000..569ff8d --- /dev/null +++ b/src/config.json @@ -0,0 +1,199 @@ +{ + "default": { + "defaultCommand": "g", + "bgColor": "#282828", + "textColor": "#ebdbb2", + "fontSize": "1.75em", + "clockSize": "2em", + "showClock": false, + "militaryClock": false, + "defaultMsgColor": "#d79921", + "errorMsgColor": "#cc241d", + "alwaysNewTab": false, + "gistID": "", + "links": [], + "separator": ";" + }, + "aliases": { + "cal": "gc", + "gk": "k", + "ddg": "dg", + "?": "help" + }, + "quickButtons": [ + { + "section": "Shopping", + "buttons": [ + { + "class": "fab fa-ebay", + "link": "https://ebay.it", + "title": "eBay" }, + { + "class": "fab fa-amazon", + "link": "https://amazon.it", + "title": "Amazon" + }, + { + "class": "fas fa-hamburger", + "link": "https://deliveroo.it", + "title": "Deliveroo" + }, + { + "class": "fas fa-pizza-slice", + "link": "https://justeat.it", + "title": "JUSTEAT" + } + ] + }, + { + "section": "Social", + "buttons": [ + { + "class": "fab fa-reddit", + "link": "https://reddit.com", + "title": "Reddit" + }, + { + "class": "fab fa-linkedin", + "link": "https://linkedin.com", + "title": "LinkedIn" + }, + { + "class": "fab fa-twitter", + "link": "https://twitter.com", + "title": "Twitter" + }, + { + "class": "fab fa-flickr", + "link": "https://flickr.com", + "title": "Flickr" + } + ] + }, + { + "section": "Chat", + "buttons": [ + { + "class": "fab fa-whatsapp", + "link": "https://web.whatsapp.com", + "title": "WhatsApp" + }, + { + "class": "fab fa-telegram", + "link": "https://web.telegram.org", + "title": "Telegram" + }, + { + "class": "fab fa-discord", + "link": "https://discordapp.com", + "title": "Discord" + }, + { + "class": "fab fa-slack", + "link": "https://slack.com", + "title": "Slack" + } + ] + }, + { + "section": "Productivity", + "buttons": [ + { + "class": "fas fa-envelope", + "link": "https://gmail.com", + "title": "Gmail" + }, + { + "class": "fab fa-google-drive", + "link": "https://drive.google.com", + "title": "Google Drive" + }, + { + "class": "far fa-calendar-alt", + "link": "https://calendar.google.com", + "title": "Google Calendar" + }, + { + "class": "fab fa-trello", + "link": "https://trello.com", + "title": "Trello" + } + ] + }, + { + "section": "Streaming", + "buttons": [ + { + "class": "fas fa-film", + "link": "https://netflix.com", + "title": "Netflix" + }, + { + "class": "fas fa-play-circle", + "link": "https://primevideo.com", + "title": "Prime Video" + }, + { + "class": "fab fa-youtube", + "link": "https://youtube.com", + "title": "YouTube" + }, + { + "class": "fab fa-twitch", + "link": "https://twitch.tv", + "title": "Twitch" + }, + { + "class": "fab fa-spotify", + "link": "https://open.spotify.com", + "title": "Spotify" + } + ] + }, + { + "section": "Code", + "buttons": [ + { + "class": "fab fa-github", + "link": "https://github.com", + "title": "GitHub" + }, + { + "class": "fab fa-gitlab", + "link": "https://gitlab.com", + "title": "GitLab" + }, + { + "class": "fas fa-laptop-code", + "link": "https://codesandbox.io", + "title": "CodeSandbox" + }, + { + "class": "fab fa-codepen", + "link": "https://codepen.io", + "title": "CodePen" + }, + { + "class": "fab fa-stack-overflow", + "link": "https://stackoverflow.com", + "title": "StackOverflow" + } + ] + }, + { + "section": "Games", + "buttons": [ + { + "class": "fab fa-steam", + "link": "https://steampowered.com", + "title": "Steam" + }, + { + "class": "fas fa-gamepad", + "link": "https://gog.com", + "title": "GOG" + } + ] + } + ] +} diff --git a/src/index.js b/src/index.js index 4e9303f..c839def 100644 --- a/src/index.js +++ b/src/index.js @@ -1,1108 +1,967 @@ -import './style.css' -;(function () { - // Default config - let CONFIG = { - defaultCommand: 'g', - bgColor: '#282828', - textColor: '#ebdbb2', - fontSize: '1.75em', - clockSize: '2em', - showClock: false, - militaryClock: false, - defaultMsgColor: '#d79921', - errorMsgColor: '#cc241d', - alwaysNewTab: false, - gistID: '', - links: [], - separator: ';', - } - const DEFAULT_CONFIG = Object.assign({}, CONFIG) - let aliases = { - // alias: command - cal: 'gc', - gk: 'k', - ddg: 'dg', - '?': 'help', - } - let newTab = false - let lastEnteredCommand = '' - let messageTimer = null - - window.onload = () => { - loadConfig() - applyConfig() - saveConfig() - addQuickButtons() +import { addQuickButtons } from './quickButtons'; - document.querySelector('#input').focus() +import config from './config.json'; - document.querySelector('body').addEventListener('click', () => { - document.querySelector('#input').focus() - }) +import './style.css'; - document.onkeydown = handleKeyDown +let CONFIG = config.default; +const DEFAULT_CONFIG = Object.assign({}, config.default); +const { aliases } = config; +let newTab = false; +let lastEnteredCommand = ''; +let messageTimer = null; - updateClock() - } +window.onload = () => { + loadConfig(); + applyConfig(); + saveConfig(); + addQuickButtons(); - function addQuickButtons() { - const QUICK_BUTTONS = [ - { - section: 'Shopping', - buttons: [ - { - class: 'fab fa-ebay', - link: 'https://ebay.it', - title: 'eBay', - }, - { - class: 'fab fa-amazon', - link: 'https://amazon.it', - title: 'Amazon', - }, - { - class: 'fas fa-hamburger', - link: 'https://deliveroo.it', - title: 'Deliveroo', - }, - { - class: 'fas fa-pizza-slice', - link: 'https://justeat.it', - title: 'JUSTEAT', - }, - ], - }, - { - section: 'Social', - buttons: [ - { - class: 'fab fa-reddit', - link: 'https://reddit.com', - title: 'Reddit', - }, - { - class: 'fab fa-linkedin', - link: 'https://linkedin.com', - title: 'LinkedIn', - }, - { - class: 'fab fa-twitter', - link: 'https://twitter.com', - title: 'Twitter', - }, - { - class: 'fab fa-flickr', - link: 'https://flickr.com', - title: 'Flickr', - }, - ], - }, - { - section: 'Chat', - buttons: [ - { - class: 'fab fa-whatsapp', - link: 'https://web.whatsapp.com', - title: 'WhatsApp', - }, - { - class: 'fab fa-telegram', - link: 'https://web.telegram.org', - title: 'Telegram', - }, - { - class: 'fab fa-discord', - link: 'https://discordapp.com', - title: 'Discord', - }, - { - class: 'fab fa-slack', - link: 'https://slack.com', - title: 'Slack', - }, - ], - }, - { - section: 'Productivity', - buttons: [ - { - class: 'fas fa-envelope', - link: 'https://gmail.com', - title: 'Gmail', - }, - { - class: 'fab fa-google-drive', - link: 'https://drive.google.com', - title: 'Google Drive', - }, - { - class: 'far fa-calendar-alt', - link: 'https://calendar.google.com', - title: 'Google Calendar', - }, - { - class: 'fab fa-trello', - link: 'https://trello.com', - title: 'Trello', - }, - ], - }, - { - section: 'Streaming', - buttons: [ - { - class: 'fas fa-film', - link: 'https://netflix.com', - title: 'Netflix', - }, - { - class: 'fas fa-play-circle', - link: 'https://primevideo.com', - title: 'Prime Video', - }, - { - class: 'fab fa-youtube', - link: 'https://youtube.com', - title: 'YouTube', - }, - { - class: 'fab fa-twitch', - link: 'https://twitch.tv', - title: 'Twitch', - }, - { - class: 'fab fa-spotify', - link: 'https://open.spotify.com', - title: 'Spotify', - }, - ], - }, - { - section: 'Code', - buttons: [ - { - class: 'fab fa-github', - link: 'https://github.com', - title: 'GitHub', - }, - { - class: 'fab fa-gitlab', - link: 'https://gitlab.com', - title: 'GitLab', - }, - { - class: 'fas fa-laptop-code', - link: 'https://codesandbox.io', - title: 'CodeSandbox', - }, - { - class: 'fab fa-codepen', - link: 'https://codepen.io', - title: 'CodePen', - }, - { - class: 'fab fa-stack-overflow', - link: 'https://stackoverflow.com', - title: 'StackOverflow', - }, - ], - }, - { - section: 'Games', - buttons: [ - { - class: 'fab fa-steam', - link: 'https://steampowered.com', - title: 'Steam', - }, - { - class: 'fas fa-gamepad', - link: 'https://gog.com', - title: 'GOG', - }, - ], - }, - ] - - const qbEl = document.querySelector('#quick-buttons') - - QUICK_BUTTONS.forEach(section => { - const sectionEl = document.createElement('section') - - const getSvg = name => { - const TYPES = { - b: 'brands', - r: 'regular', - s: 'solid', - } + document.querySelector('#input').focus(); - const type = TYPES[name[2]] - const fileName = name.slice(7) + document.querySelector('body').addEventListener('click', () => { + document.querySelector('#input').focus(); + }); - return require(`!raw-loader!@fortawesome/fontawesome-free/svgs/${type}/${fileName}.svg`) - .default - } + document.onkeydown = handleKeyDown; - const buttonsHtml = section.buttons - .map( - button => - `
  • ${getSvg( - button.class - )}
  • ` - ) - .join('') - - sectionEl.innerHTML += buttonsHtml - qbEl.appendChild(sectionEl) - }) - } + updateClock(); +}; - function evaluateInput() { - let input = document.querySelector('#input').value.trim() - document.querySelector('#input').value = '' - clearMessage() +const evaluateInput = () => { + const input = document.querySelector('#input').value.trim(); + document.querySelector('#input').value = ''; + clearMessage(); - // Input is empty - if (input === '') return + // Input is empty + if (input === '') { + return; + } - // Save one-line history - lastEnteredCommand = input + // Save one-line history + lastEnteredCommand = input; - // Format input - let args = input.split(CONFIG.separator) - let command = args[0].toLowerCase() - for (let i = 0; i < args.length; i++) { - args[i] = args[i].trim() - } + // Format input + const args = input.split(CONFIG.separator); + let command = args[0].toLowerCase(); + for (let i = 0; i < args.length; i += 1) { + args[i] = args[i].trim(); + } - // Check if valid command or alias - const commandList = Object.keys(commands) - const aliasList = Object.keys(aliases) - let validCommand = false - for (let i = 0; i < commandList.length; i++) { - if (command === commandList[i]) { - validCommand = true - args.shift() // remove command from args - break - } else if (command === aliasList[i]) { - validCommand = true - command = aliases[command] - args.shift() - break - } + // Check if valid command or alias + const commandList = Object.keys(commands); + const aliasList = Object.keys(aliases); + let validCommand = false; + for (let i = 0; i < commandList.length; i += 1) { + if (command === commandList[i]) { + validCommand = true; + args.shift(); // remove command from args + break; + } else if (command === aliasList[i]) { + validCommand = true; + command = aliases[command]; + args.shift(); + break; } + } - // Check if URL - let isURL = false - if (checkIfURL(args[0])) { - isURL = true - command = args.shift() - } + // Check if URL + let isURL = false; + if (checkIfURL(args[0])) { + isURL = true; + command = args.shift(); + } - // Check if valid link - let validLink = false - if (!isURL && !validCommand) { - // ensure shortcut not taken - for (let i = 0; i < CONFIG.links.length; i++) { - if (CONFIG.links[i].command == command) { - validLink = true - command = args.shift() - break - } + // Check if valid link + let validLink = false; + if (!isURL && !validCommand) { + // ensure shortcut not taken + for (let i = 0; i < CONFIG.links.length; i += 1) { + if (CONFIG.links[i].command === command) { + validLink = true; + command = args.shift(); + break; } } + } - // Check for newtab flag - if (args[args.length - 1] === 'n') { - newTab = true - args.pop() // remove newtab flag - } + // Check for newtab flag + if (args[args.length - 1] === 'n') { + newTab = true; + args.pop(); // remove newtab flag + } - // Execute - if (isURL) { - redirect(buildURL(command)) - } else if (validCommand) { - commands[command](args) - } else if (validLink) { - let link = getFullLink(command) - if (args.length == 0) redirect(link.url) - else redirect(link.url + link.search + args.join(' ')) + // Execute + if (isURL) { + redirect(buildURL(command)); + } else if (validCommand) { + commands[command](args); + } else if (validLink) { + const link = getFullLink(command); + if (args.length === 0) { + redirect(link.url); } else { - commands[CONFIG['defaultCommand']](args) + redirect(link.url + link.search + args.join(' ')); } - - return false + } else { + commands[CONFIG['defaultCommand']](args); } - - // Opens a URL either in current or new tab - function redirect(url) { - if (newTab || CONFIG.alwaysNewTab) window.open(url, '_blank').focus() - else window.location.href = url - - newTab = false - return false +}; + +// Opens a URL either in current or new tab +const redirect = url => { + if (newTab || CONFIG.alwaysNewTab) { + window.open(url, '_blank').focus(); + } else { + window.location.href = url; } - function loadConfig() { - // Proceed if storage supported - if (Storage) { - // Create config object if it doesn't exist - if (localStorage.getItem('taabSettings') === null) { - localStorage.setItem('taabSettings', JSON.stringify(DEFAULT_CONFIG)) - // Otherwise load saved config from localStorage - } else { - const savedConfig = JSON.parse(localStorage.getItem('taabSettings')) - // Merge new settings - CONFIG = Object.assign(CONFIG, savedConfig) - } - - // Legacy import - if (localStorage.getItem('customCommands') !== null) { - importLegacyLinks() - localStorage.removeItem('customCommands') - } + newTab = false; + return false; +}; + +const loadConfig = () => { + // Proceed if storage supported + if (Storage) { + // Create config object if it doesn't exist + if (localStorage.getItem('taabSettings') === null) { + localStorage.setItem('taabSettings', JSON.stringify(DEFAULT_CONFIG)); + // Otherwise load saved config from localStorage + } else { + const savedConfig = JSON.parse(localStorage.getItem('taabSettings')); + // Merge new settings + CONFIG = Object.assign(CONFIG, savedConfig); } - } - function applyConfig() { - // Text and background colors - document.body.style.backgroundColor = CONFIG.bgColor - document.body.style.color = CONFIG.textColor - document.body.style.fontSize = CONFIG.fontSize - - // Clock - const clock = document.querySelector('#clock') - clock.style.fontSize = CONFIG.clockSize - if (CONFIG.showClock) clock.style.display = 'inline' - else clock.style.display = 'none' + // Legacy import + if (localStorage.getItem('customCommands') !== null) { + importLegacyLinks(); + localStorage.removeItem('customCommands'); + } } - - function saveConfig() { - // Write to localStorage - localStorage.setItem('taabSettings', JSON.stringify(CONFIG)) +}; + +const applyConfig = () => { + // Text and background colors + document.body.style.backgroundColor = CONFIG.bgColor; + document.body.style.color = CONFIG.textColor; + document.body.style.fontSize = CONFIG.fontSize; + + // Clock + const clock = document.querySelector('#clock'); + clock.style.fontSize = CONFIG.clockSize; + if (CONFIG.showClock) { + clock.style.display = 'inline'; + } else { + clock.style.display = 'none'; } +}; - function displayMessage(msg, timeMs, color = CONFIG.defaultMsgColor) { - let msgDiv = document.querySelector('#message') - - msgDiv.style.color = color +const saveConfig = () => { + // Write to localStorage + localStorage.setItem('taabSettings', JSON.stringify(CONFIG)); +}; - // Clear existing timer/message - if (messageTimer) { - msgDiv.innerHTML = '' - clearTimeout(messageTimer) - } - - // Display message - msgDiv.innerHTML = msg - - // Set timer - messageTimer = setTimeout(() => { - msgDiv.innerHTML = '' - }, timeMs) - } +const displayMessage = (msg, timeMs, color = CONFIG.defaultMsgColor) => { + const msgDiv = document.querySelector('#message'); - function displayErrorMessage(msg, timeMs) { - displayMessage(msg, timeMs, CONFIG.errorMsgColor) - } + msgDiv.style.color = color; - function clearMessage() { - document.querySelector('#message').innerHTML = '' + // Clear existing timer/message + if (messageTimer) { + msgDiv.innerHTML = ''; + clearTimeout(messageTimer); } - // Adds protocol if not present, encodes search string - function buildURL(url, search = '', query = '') { - let dest = /(http(s)?:\/\/.)/.test(url) ? url : 'http://' + url - return dest + search + encodeURIComponent(query) + // Display message + msgDiv.innerHTML = msg; + + // Set timer + messageTimer = setTimeout(() => { + msgDiv.innerHTML = ''; + }, timeMs); +}; + +const displayErrorMessage = (msg, timeMs) => { + displayMessage(msg, timeMs, CONFIG.errorMsgColor); +}; + +const clearMessage = () => { + document.querySelector('#message').innerHTML = ''; +}; + +// Adds protocol if not present, encodes search string +const buildURL = (url, search = '', query = '') => { + const dest = /(http(s)?:\/\/.)/.test(url) ? url : 'http://' + url; + return dest + search + encodeURIComponent(query); +}; + +const updateClock = () => { + const d = new Date(); + let h = d.getHours(); + if (!CONFIG.militaryClock && h > 12) { + h -= 12; } - - function updateClock() { - let d = new Date() - let h = d.getHours() - if (!CONFIG.militaryClock && h > 12) h -= 12 - let hours = h.toString() - let minutes = ('0' + d.getMinutes()).slice(-2) - document.querySelector('#clock').innerText = `${hours}:${minutes}` - setTimeout(updateClock, 1000) + const hours = h.toString(); + const minutes = ('0' + d.getMinutes()).slice(-2); + document.querySelector('#clock').innerText = `${hours}:${minutes}`; + setTimeout(updateClock, 1000); +}; + +const handleKeyDown = e => { + const keycode = e.which || e.keyCode; + + // Enter key + if (keycode === 13) { + evaluateInput(); } - function handleKeyDown(e) { - let keycode = e.which || e.keyCode - - // Enter key - if (keycode === 13) { - evaluateInput() - } - - // Up arrow - // Replace input text with last entered command - else if (keycode === 38) { - if (lastEnteredCommand !== '') { - let input = document.querySelector('#input') - input.focus() - input.value = lastEnteredCommand - // Put cursor at end of text - setTimeout(() => { - input.setSelectionRange(input.value.length, input.value.length) - }, 2) - } + // Up arrow + // Replace input text with last entered command + else if (keycode === 38) { + if (lastEnteredCommand !== '') { + const input = document.querySelector('#input'); + input.focus(); + input.value = lastEnteredCommand; + // Put cursor at end of text + setTimeout(() => { + input.setSelectionRange(input.value.length, input.value.length); + }, 2); } } - - function fetchGist(gistID) { - let xhr = new XMLHttpRequest() - let url = `https://api.github.com/gists/${gistID}` - xhr.onreadystatechange = function () { - if (xhr.readyState == 4 && xhr.status == 200) { - let files = JSON.parse(xhr.responseText).files - if (files.length > 1) { - displayErrorMessage( - 'Error: Multiple files found in gist. Please use a gist with only one file.', - 5000 - ) - return - } - let gistText = files[Object.keys(files)[0]].content - updateConfig(gistText, gistID) +}; + +const fetchGist = gistID => { + const xhr = new XMLHttpRequest(); + const url = `https://api.github.com/gists/${gistID}`; + xhr.onreadystatechange = () => { + if (xhr.readyState === 4 && xhr.status === 200) { + const { files } = JSON.parse(xhr.responseText); + if (files.length > 1) { + displayErrorMessage( + 'Error: Multiple files found in gist. Please use a gist with only one file.', + 5000 + ); + return; } + const gistText = files[Object.keys(files)[0]].content; + updateConfig(gistText, gistID); } - xhr.open('GET', url, true) - xhr.send(null) + }; + xhr.open('GET', url, true); + xhr.send(null); +}; + +const updateConfig = (configString, gist) => { + let config; + try { + config = JSON.parse(configString); + } catch (err) { + displayErrorMessage('Error parsing config, see console for details', 5000); + console.error(err); + return; } - function updateConfig(configString, gist) { - let config - try { - config = JSON.parse(configString) - } catch (err) { - displayErrorMessage('Error parsing config, see console for details', 5000) - console.log(err) - return - } - - for (let setting in config) { - CONFIG[setting] = config[setting] - } - CONFIG.gistID = gist - - saveConfig() - applyConfig() - displayMessage('Config imported', 5000) + for (const setting in config) { + CONFIG[setting] = config[setting]; } - - function checkIfURL(url) { - if ( - /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/.test( - url - ) - ) { - if (!url.includes(' ')) { - return true - } + CONFIG.gistID = gist; + + saveConfig(); + applyConfig(); + displayMessage('Config imported', 5000); +}; + +const checkIfURL = url => { + if ( + /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/.test( + url + ) + ) { + if (!url.includes(' ')) { + return true; } - return false } - - // Get full link object from its shortcut - function getFullLink(shortcut) { - for (let i = 0; i < CONFIG.links.length; i++) { - if (shortcut == CONFIG.links[i].command) { - return CONFIG.links[i] - } + return false; +}; + +// Get full link object from its shortcut +const getFullLink = shortcut => { + for (let i = 0; i < CONFIG.links.length; i += 1) { + if (shortcut === CONFIG.links[i].command) { + return CONFIG.links[i]; } - return null } - - // Import legacy links (custom commands) - function importLegacyLinks() { - const legacyLinks = JSON.parse(localStorage.getItem('customCommands')) - if (legacyLinks) { - CONFIG.links = legacyLinks - saveConfig() - } + return null; +}; + +// Import legacy links (custom commands) +const importLegacyLinks = () => { + const legacyLinks = JSON.parse(localStorage.getItem('customCommands')); + if (legacyLinks) { + CONFIG.links = legacyLinks; + saveConfig(); } +}; + +const commands = { + // Amazon + a: args => { + const url = 'https://amazon.com', + search = '/s/?field-keywords='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Config + config: args => { + switch (args[0]) { + case 'export': { + // Display config as string and select all of it + displayMessage(localStorage.getItem('taabSettings'), 1000 * 25); + window + .getSelection() + .selectAllChildren(document.querySelector('#message')); + break; + } - const commands = { - // Set - set: args => { - // Validate hex color values. - // #EBEBEB is valid, EBEBEB is not. #FFF is valid shorthand. - const validHex = hex => /^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(hex) + case 'import': { + updateConfig(args[1]); + break; + } - switch (args[0]) { - // Default command - case 'defaultCommand': - // Display current value if none given - if (args.length === 1) { - displayMessage(`Default command: ${CONFIG.defaultCommand}`, 5000) - break - } + case 'open': { + if (CONFIG.gistID !== '') { + newTab = true; + commands.gist([CONFIG.gistID]); + } else { + displayErrorMessage( + 'Error: No gist ID found. Make sure you have fetched your config at least once.', + 8000 + ); + } + break; + } - // Check if existant command - if (Object.keys(commands).includes(args[1])) { - CONFIG['defaultCommand'] = args[1] - displayMessage(`Set default command to ${args[1]}`, 3000) - } else { + case 'fetch': { + let gistID; + if (args.length > 1) { + try { + gistID = args[1].match(/([0-9A-Za-z]{32})/)[0]; + } catch (err) { displayErrorMessage( - `Error: command ${args[1]} not found; default command not changed`, - 10000 - ) - } - break - - // Background color - case 'bgColor': - // Display current value if none given - if (args.length === 1) { - displayMessage(`Current background color: ${CONFIG.bgColor}`, 8000) - break - } - - // Set new background color - if (validHex(args[1])) { - CONFIG.bgColor = args[1] - } else { - displayErrorMessage('Error: invalid hex value', 5000) - } - break - - // Text color - case 'textColor': - // Display current value if none given - if (args.length === 1) { - displayMessage( - `Current background color: ${CONFIG.textColor}`, + 'Error: unable to parse gist ID.
    Try entering just the 32 character ID string.', 8000 - ) - break + ); + return; } + } else if (CONFIG.gistID !== undefined) { + ({ gistID } = CONFIG); + } else { + displayErrorMessage('Error: no gist ID', 5000); + break; + } + displayMessage('Fetching gist...', 2500); + fetchGist(gistID); + break; + } + } + }, + + // DuckDuckGo + dg: args => { + const url = 'https://duckduckgo.com', + search = '/?q='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args)); + } + }, + + // Dictionary + dict: args => { + const url = 'http://dictionary.com', + search = '/browse/'; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Google + g: args => { + const url = 'https://google.com', + search = '/search?q='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args)); + } + }, + + // Google Calendar + gc: () => { + redirect('https://calendar.google.com'); + }, + + // Google Drive + gd: args => { + const url = 'https://drive.google.com', + search = '/drive/search?q='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // GitHub + gh: args => { + const url = 'https://github.com', + search = '/'; + if (args.length === 0) { + redirect(url); + } else { + redirect(url + search + args.join('')); + } + }, + + // GitHub Gist + gist: args => { + const url = 'https://gist.github.com', + search = '/'; + if (args.length === 0) { + redirect(url); + } else { + redirect(url + search + args.join('')); + } + }, + + // Gmail + gm: args => { + const url = 'https://mail.google.com', + search = '/mail/u/0/#search/'; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Help + help: () => { + newTab = true; + redirect('https://github.com/nicolalamacchia/powertab#readme'); + }, + + // Hacker News + hn: args => { + const url = 'https://news.ycombinator.com'; + if (args.length === 0) { + redirect(url); + } else { + switch (args[0]) { + case 'new': + redirect(url + '/newest'); + break; - // Set new text color - if (validHex(args[1])) { - CONFIG['textColor'] = args[1] - } else { - displayErrorMessage('Error: invalid hex value', 5000) - } - break - - case 'fontSize': - // Display current setting - if (args.length === 1) { - displayMessage(`Current input font size: ${CONFIG.fontSize}`, 8000) - break - } + case 'comments': + redirect(url + '/newcomments'); + break; - // Set new value - if (args[1]) CONFIG['fontSize'] = args[1] - break + case 'show': + redirect(url + '/show'); + break; - case 'clockSize': - // Display current setting - if (args.length === 1) { - displayMessage(`Current clock font size: ${CONFIG.clockSize}`, 8000) - break - } + case 'ask': + redirect(url + '/ask'); + break; - // Set new value - if (args[1]) CONFIG['clockSize'] = args[1] - break - - // Always new tab - case 'newtab': - case 'alwaysNewTab': - // Display current value if none given - if (args.length === 1) { - let msg = `alwaysNewTab is ${CONFIG.alwaysNewTab ? 'on' : 'off'}` - displayMessage(msg, 5000) - break - } - if (args[1] === 'on') CONFIG.alwaysNewTab = true - else if (args[1] === 'off') CONFIG.alwaysNewTab = false - else displayErrorMessage("Must be set to either 'on' or 'off'", 5000) - break - - // Clock - case 'clock': - // Display current value if none given - if (args.length === 1) { - displayMessage( - `Clock is ${CONFIG.showClock ? 'on' : 'off'}, - ${CONFIG.militaryClock ? '24' : '12'}-hour`, - 5000 - ) - break - } + case 'jobs': + redirect(url + '/jobs'); + break; - // Set on/off, 12/24 hour - switch (args[1]) { - case 'on': - CONFIG.showClock = true - break - case 'off': - CONFIG.showClock = false - break - case '12': - CONFIG.militaryClock = false - break - case '24': - CONFIG.militaryClock = true - break - default: - displayErrorMessage( - "Must be set to 'on', 'off', '12' or '24'", - 5000 - ) - } - break - - // Restore defaults - case 'defaults': - localStorage.removeItem('taabSettings') - CONFIG = DEFAULT_CONFIG - loadConfig() - applyConfig() - saveConfig() - displayMessage('Settings reset to defaults', 5000) - break - - default: - displayErrorMessage(`"${args[0]}" is not a valid setting`, 5000) + case 'submit': + redirect(url + '/submit'); + break; } - - saveConfig() - applyConfig() - }, - - // Links - link: args => { - switch (args.length) { - case 0: - displayErrorMessage( - `link is a builtin command
    To search for "link" try g${CONFIG.separator}link
    `, - 8000 - ) - break - - case 1: - // Show all links - if (args[0] === 'show') { - let msg = '' - for (let i = 0; i < CONFIG.links.length; i++) { - let link = CONFIG.links[i] - msg += `${link.command} --> ${link.url}` - if (link.search !== '') msg += ` (${link.search})` - msg += '
    ' + } + }, + + // Internet Movie Database + imdb: args => { + const url = 'http://imdb.com', + search = '/find?s=all&q='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Google Images + img: args => { + const url = 'https://google.com', + search = '/search?tbm=isch&q='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Google Keep + k: args => { + const url = 'https://keep.google.com', + search = '/#search/text='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Links + link: args => { + switch (args.length) { + case 0: + displayErrorMessage( + `link is a builtin command
    To search for "link" try g${CONFIG.separator}link
    `, + 8000 + ); + break; + + case 1: + // Show all links + if (args[0] === 'show') { + let msg = ''; + for (let i = 0; i < CONFIG.links.length; i += 1) { + const link = CONFIG.links[i]; + msg += `${link.command} --> ${link.url}`; + if (link.search !== '') { + msg += ` (${link.search})`; } - displayMessage(msg, 30000) - break + msg += '
    '; } + displayMessage(msg, 30000); + break; + } - // Show specific (existent) link - else { - let link = getFullLink(args[0]) - if (link) { - let msg = `"${args[0]}" links to ${link.url}` - if (link.search !== '') msg += ` (${link.search})` - displayMessage(msg, 10000) + // Show specific (existent) link + else { + const link = getFullLink(args[0]); + if (link) { + let msg = `"${args[0]}" links to ${link.url}`; + if (link.search !== '') { + msg += ` (${link.search})`; } - break + displayMessage(msg, 10000); } + break; + } - case 2: - case 3: - // Delete - if (args[1] === 'delete') { - for (let i = 0; i < CONFIG.links.length; i++) { - if (args[0] == CONFIG.links[i].command) { - CONFIG.links.splice(i, 1) - displayMessage(`Link ${args[0]} deleted`, 5000) - } + case 2: + case 3: + // Delete + if (args[1] === 'delete') { + for (let i = 0; i < CONFIG.links.length; i += 1) { + if (args[0] === CONFIG.links[i].command) { + CONFIG.links.splice(i, 1); + displayMessage(`Link ${args[0]} deleted`, 5000); } } + } - // Add new - else { - // Ensure shortcut not taken - for (let i = 0; i < CONFIG.links.length; i++) { - if (CONFIG.links[i].command == args[0]) { - // Already using this shortcut, override? - if (confirm('Overwrite existing shortcut?')) { - // Remove existing shortcut if user says yes to avoid duplicate link commands - for (let i = 0; i < CONFIG.links.length; i++) { - if (CONFIG.links[i].command == args[0]) { - CONFIG.links.splice(i, 1) - } + // Add new + else { + // Ensure shortcut not taken + for (let i = 0; i < CONFIG.links.length; i += 1) { + if (CONFIG.links[i].command === args[0]) { + // Already using this shortcut, override? + if (confirm('Overwrite existing shortcut?')) { + // Remove existing shortcut if user says yes to avoid duplicate link commands + for (let i = 0; i < CONFIG.links.length; i += 1) { + if (CONFIG.links[i].command === args[0]) { + CONFIG.links.splice(i, 1); } - } else { - // Do nothing if user says no - return } + } else { + // Do nothing if user says no + return; } } - if ( - Object.keys(commands).includes(args[0]) || - Object.keys(aliases).includes(args[0]) - ) { - displayErrorMessage( - `Cannot override builtin command: ${args[0]}`, - 5000 - ) - return - } - - // Check that URL is valid - let url = buildURL(args[1]) - if (checkIfURL(url)) { - CONFIG.links.push({ - command: args[0], - url: url, - search: args[2] || '', - }) - } else { - displayErrorMessage('Invalid URL', 5000) - return - } } - break - } - - saveConfig() - }, - - // Config - config: args => { - switch (args[0]) { - case 'export': - // Display config as string and select all of it - displayMessage(localStorage.getItem('taabSettings'), 1000 * 25) - window - .getSelection() - .selectAllChildren(document.querySelector('#message')) - break - - case 'import': - updateConfig(args[1]) - break - - case 'open': - if (CONFIG.gistID !== '') { - newTab = true - commands.gist([CONFIG.gistID]) - } else { + if ( + Object.keys(commands).includes(args[0]) || + Object.keys(aliases).includes(args[0]) + ) { displayErrorMessage( - 'Error: No gist ID found. Make sure you have fetched your config at least once.', - 8000 - ) - } - break - - case 'fetch': - let gistID - if (args.length > 1) { - try { - gistID = args[1].match(/([0-9A-Za-z]{32})/)[0] - } catch (err) { - displayErrorMessage( - 'Error: unable to parse gist ID.
    Try entering just the 32 character ID string.', - 8000 - ) - return - } - } else if (CONFIG.gistID != undefined) { - gistID = CONFIG.gistID - } else { - displayErrorMessage('Error: no gist ID', 5000) - break + `Cannot override builtin command: ${args[0]}`, + 5000 + ); + return; } - displayMessage('Fetching gist...', 2500) - fetchGist(gistID) - break - } - }, - - // Help - help: args => { - newTab = true - redirect('https://github.com/nicolalamacchia/powertab#readme') - }, - - // Google - g: args => { - const url = 'https://google.com', - search = '/search?q=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args)) - }, - - // DuckDuckGo - dg: args => { - const url = 'https://duckduckgo.com', - search = '/?q=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args)) - }, - - // Reddit - r: args => { - const url = 'https://reddit.com', - search = '/r/' - let query = args.length > 0 ? args[0] : '' - - const validSort = sort => { - return [ - 'hot', - 'new', - 'rising', - 'controversial', - 'top', - 'gilded', - 'wiki', - 'promoted', - ].includes(sort) - } - const validRange = range => { - return ['day', 'week', 'month', 'year', 'all'].includes(range) - } - switch (args.length) { - // Given nothing - case 0: - redirect(url) - break - - // Given a subreddit - case 1: - redirect(buildURL(url, search, args[0])) - break - - // Given subreddit and sort - case 2: - query += validSort(args[1]) ? '/' + args[1] : '' - redirect(url + search + query) - break - - // Given subreddit, sort and range - case 3: - if (['top', 'controversial'].includes(args[1])) { - query += validRange(args[2]) ? '/' + args[1] + '?t=' + args[2] : '' + // Check that URL is valid + const url = buildURL(args[1]); + if (checkIfURL(url)) { + CONFIG.links.push({ + command: args[0], + search: args[2] || '', + url, + }); } else { - query += validSort(args[1]) ? '/' + args[1] : '' + displayErrorMessage('Invalid URL', 5000); + return; } - redirect(url + search + query) - break - } - }, + } + break; + } - // Hacker News - hn: args => { - const url = 'https://news.ycombinator.com' - if (args.length == 0) { - redirect(url) - } else { - switch (args[0]) { - case 'new': - redirect(url + '/newest') - break - - case 'comments': - redirect(url + '/newcomments') - break - - case 'show': - redirect(url + '/show') - break - - case 'ask': - redirect(url + '/ask') - break - - case 'jobs': - redirect(url + '/jobs') - break - - case 'submit': - redirect(url + '/submit') - break + saveConfig(); + }, + + // Google Maps + map: args => { + const url = 'https://google.com/maps', + search = '/search/'; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // MDN web docs + mdn: args => { + const url = 'https://developer.mozilla.org', + search = '/search?q='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Netflix + n: args => { + const url = 'https://netflix.com', + search = '/search?q='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Node package manager + npm: args => { + const url = 'https://npmjs.org', + search = '/search?q='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Python package index + pypi: args => { + const url = 'https://pypi.org', + search = '/search/?q='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Reddit + r: args => { + const url = 'https://reddit.com', + search = '/r/'; + let query = args.length > 0 ? args[0] : ''; + + const validSort = sort => { + return [ + 'hot', + 'new', + 'rising', + 'controversial', + 'top', + 'gilded', + 'wiki', + 'promoted', + ].includes(sort); + }; + const validRange = range => { + return ['day', 'week', 'month', 'year', 'all'].includes(range); + }; + + switch (args.length) { + // Given nothing + case 0: + redirect(url); + break; + + // Given a subreddit + case 1: + redirect(buildURL(url, search, args[0])); + break; + + // Given subreddit and sort + case 2: + query += validSort(args[1]) ? '/' + args[1] : ''; + redirect(url + search + query); + break; + + // Given subreddit, sort and range + case 3: + if (['top', 'controversial'].includes(args[1])) { + query += validRange(args[2]) ? '/' + args[1] + '?t=' + args[2] : ''; + } else { + query += validSort(args[1]) ? '/' + args[1] : ''; } - } - }, - - // Youtube - y: args => { - const url = 'https://youtube.com', - search = '/results?search_query=' - if (args.length == 0) { - redirect(url) + redirect(url + search + query); + break; + } + }, + + // Set + set: args => { + // Validate hex color values. + // #EBEBEB is valid, EBEBEB is not. #FFF is valid shorthand. + const validHex = hex => /^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(hex); + + switch (args[0]) { + // Default command + case 'defaultCommand': + // Display current value if none given + if (args.length === 1) { + displayMessage(`Default command: ${CONFIG.defaultCommand}`, 5000); + break; + } + + // Check if existant command + if (Object.keys(commands).includes(args[1])) { + CONFIG['defaultCommand'] = args[1]; + displayMessage(`Set default command to ${args[1]}`, 3000); + } else { + displayErrorMessage( + `Error: command ${args[1]} not found; default command not changed`, + 10000 + ); + } + break; + + // Background color + case 'bgColor': + // Display current value if none given + if (args.length === 1) { + displayMessage(`Current background color: ${CONFIG.bgColor}`, 8000); + break; + } + + // Set new background color + if (validHex(args[1])) { + CONFIG.bgColor = args[1]; + } else { + displayErrorMessage('Error: invalid hex value', 5000); + } + break; + + // Text color + case 'textColor': + // Display current value if none given + if (args.length === 1) { + displayMessage(`Current background color: ${CONFIG.textColor}`, 8000); + break; + } + + // Set new text color + if (validHex(args[1])) { + CONFIG['textColor'] = args[1]; + } else { + displayErrorMessage('Error: invalid hex value', 5000); + } + break; + + case 'fontSize': + // Display current setting + if (args.length === 1) { + displayMessage(`Current input font size: ${CONFIG.fontSize}`, 8000); + break; + } + + // Set new value + if (args[1]) { + CONFIG['fontSize'] = args[1]; + } + break; + + case 'clockSize': + // Display current setting + if (args.length === 1) { + displayMessage(`Current clock font size: ${CONFIG.clockSize}`, 8000); + break; + } + + // Set new value + if (args[1]) { + CONFIG['clockSize'] = args[1]; + } + break; + + // Always new tab + case 'newtab': + case 'alwaysNewTab': + // Display current value if none given + if (args.length === 1) { + const msg = `alwaysNewTab is ${CONFIG.alwaysNewTab ? 'on' : 'off'}`; + displayMessage(msg, 5000); + break; + } + if (args[1] === 'on') { + CONFIG.alwaysNewTab = true; + } else if (args[1] === 'off') { + CONFIG.alwaysNewTab = false; + } else { + displayErrorMessage("Must be set to either 'on' or 'off'", 5000); + } + break; + + // Clock + case 'clock': + // Display current value if none given + if (args.length === 1) { + displayMessage( + `Clock is ${CONFIG.showClock ? 'on' : 'off'}, + ${CONFIG.militaryClock ? '24' : '12'}-hour`, + 5000 + ); + break; + } + + // Set on/off, 12/24 hour + switch (args[1]) { + case 'on': + CONFIG.showClock = true; + break; + case 'off': + CONFIG.showClock = false; + break; + case '12': + CONFIG.militaryClock = false; + break; + case '24': + CONFIG.militaryClock = true; + break; + default: + displayErrorMessage( + "Must be set to 'on', 'off', '12' or '24'", + 5000 + ); + } + break; + + // Restore defaults + case 'defaults': + localStorage.removeItem('taabSettings'); + CONFIG = DEFAULT_CONFIG; + loadConfig(); + applyConfig(); + saveConfig(); + displayMessage('Settings reset to defaults', 5000); + break; + + default: + displayErrorMessage(`"${args[0]}" is not a valid setting`, 5000); + } + + saveConfig(); + applyConfig(); + }, + + // Stack Overflow + so: args => { + const url = 'https://stackoverflow.com', + search = '/search?q='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Thesaurus + thes: args => { + const url = 'http://thesaurus.com', + search = '/browse/'; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Trello + tr: args => { + const url = 'https://trello.com', + search = '/search?q='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Wikipedia + w: args => { + const url = 'https://wikipedia.org', + search = '/w/index.php?title=Special:Search&search='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Wolfram Alpha + wa: args => { + const url = 'http://wolframalpha.com', + search = '/input/?i='; + if (args.length === 0) { + redirect(url); + } else { + redirect(buildURL(url, search, args.join(' '))); + } + }, + + // Youtube + y: args => { + const url = 'https://youtube.com', + search = '/results?search_query='; + if (args.length === 0) { + redirect(url); + } else { + if (['subs', 's'].includes(args[0])) { + redirect(url + '/feed/subscriptions'); } else { - if (['subs', 's'].includes(args[0])) - redirect(url + '/feed/subscriptions') - else redirect(buildURL(url, search, args[0])) + redirect(buildURL(url, search, args[0])); } - }, - - // Wikipedia - w: args => { - const url = 'https://wikipedia.org', - search = '/w/index.php?title=Special:Search&search=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // GitHub - gh: args => { - const url = 'https://github.com', - search = '/' - if (args.length == 0) redirect(url) - else redirect(url + search + args.join('')) - }, - - // GitHub Gist - gist: args => { - const url = 'https://gist.github.com', - search = '/' - if (args.length == 0) redirect(url) - else redirect(url + search + args.join('')) - }, - - // Wolfram Alpha - wa: args => { - const url = 'http://wolframalpha.com', - search = '/input/?i=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Netflix - n: args => { - const url = 'https://netflix.com', - search = '/search?q=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Internet Movie Database - imdb: args => { - const url = 'http://imdb.com', - search = '/find?s=all&q=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Google Maps - map: args => { - const url = 'https://google.com/maps', - search = '/search/' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Google Drive - gd: args => { - const url = 'https://drive.google.com', - search = '/drive/search?q=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Google Calendar - gc: args => { - redirect('https://calendar.google.com') - }, - - // Google Images - img: args => { - const url = 'https://google.com', - search = '/search?tbm=isch&q=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Gmail - gm: args => { - const url = 'https://mail.google.com', - search = '/mail/u/0/#search/' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Google Keep - k: args => { - const url = 'https://keep.google.com', - search = '/#search/text=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Trello - tr: args => { - const url = 'https://trello.com', - search = '/search?q=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Dictionary - dict: args => { - const url = 'http://dictionary.com', - search = '/browse/' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Thesaurus - thes: args => { - const url = 'http://thesaurus.com', - search = '/browse/' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Amazon - a: args => { - const url = 'https://amazon.com', - search = '/s/?field-keywords=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Node package manager - npm: args => { - const url = 'https://npmjs.org', - search = '/search?q=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Python package index - pypi: args => { - const url = 'https://pypi.org', - search = '/search/?q=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // Stack Overflow - so: args => { - const url = 'https://stackoverflow.com', - search = '/search?q=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - - // MDN web docs - mdn: args => { - const url = 'https://developer.mozilla.org', - search = '/search?q=' - if (args.length == 0) redirect(url) - else redirect(buildURL(url, search, args.join(' '))) - }, - } - - if ('serviceWorker' in navigator) { - window.addEventListener('load', () => { - navigator.serviceWorker.register('sw.js').catch(err => { - console.error(err) - }) - }) - } -})() + } + }, +}; + +if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + navigator.serviceWorker.register('sw.js').catch(err => { + console.error(err); + }); + }); +} diff --git a/src/quickButtons.js b/src/quickButtons.js new file mode 100644 index 0000000..45bf352 --- /dev/null +++ b/src/quickButtons.js @@ -0,0 +1,35 @@ +import config from './config.json'; + +export const addQuickButtons = () => { + const qbEl = document.querySelector('#quick-buttons'); + + config.quickButtons.forEach(section => { + const sectionEl = document.createElement('section'); + + const getSvg = name => { + const TYPES = { + b: 'brands', + r: 'regular', + s: 'solid', + }; + + const type = TYPES[name[2]]; + const fileName = name.slice(7); + + return require(`!raw-loader!@fortawesome/fontawesome-free/svgs/${type}/${fileName}.svg`) + .default; + }; + + const buttonsHtml = section.buttons + .map( + button => + `
  • ${getSvg( + button.class + )}
  • ` + ) + .join(''); + + sectionEl.innerHTML += buttonsHtml; + qbEl.appendChild(sectionEl); + }); +};