RF Dashboard - Chrome Extension Dashboard
RF Dashboard adalah aplikasi chrome extension yang berfungsi sebagai custom dashboard (new tab).
Cara Kerja
Aplikasi ini, jika sudah diinstall di Chrome atau Brave, akan menggantikan halaman new tab default dari browser-browser tersebut.
Dashboard ini dilengkapi dengan fitur search Google secara custom dengan beragam site search (site:namadomain.com) yang berhubungan dengan topik pemrograman.
Beberapa fitur dashboard ini adalah:
- Search Wikipedia
- Search YouTube
- Search Tokopedia
- Search Google
- Search Reddit inside Google
- Search Quora inside Google
- Search Github inside Google
- Search FreeCodeCamp inside Google
- Search Medium inside Google
- Search Dev.To inside Google
- Search Hackernoon inside Google
- Search Codeproject inside Google
- Search Forum XDA Developers inside Google
- Search TomsHardware inside Google
- Search StackOverflow inside Google
- Search ServerFault inside Google
- Search SuperUser inside Google
- Search AskUbuntu inside Google
- Dan lain-lain
Teknologi yang Digunakan
- HTML
- CSS
- JavaScript
- Chrome Extension API
Screenshot
Rekonstruksi
Untuk membuat chrome extension seperti ini, siapkan sebuah gambar SVG.
Dalam konteks ini, saya menggunakan SVG bernama hypnotize.
Beri nama svg tersebut "hypnotize.svg". Ini untuk background di CSS.
Kemudian konversi menjadi PNG dengan nama "hypnotize.png". Ini untuk favicon.
Selanjutnya buatlah sebuah folder kosong, kemudian masukkan kedua gambar tadi ke dalamnya.
Selanjutnya, masih di folder kosong tersebut, buat script-script ini:
- index.html
- index.js
- index.css
- dummy.html
- dummy.js
- manifest.json
Berikut ini adalah isi dari "manifest.json":
{
"name": "RF Dashboard",
"version": "1.0.0",
"manifest_version": 3,
"chrome_url_overrides": {
"newtab": "dummy.html"
},
"icons": {
"16": "hypnotize.png",
"48": "hypnotize.png",
"128": "hypnotize.png"
},
"permissions": ["storage"]
}
Berikut ini adalah isi dari "index.html":
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>RF Dashboard</title>
<link
id="favicon"
rel="shortcut icon"
type="image/png"
href="hypnotize.png" />
<link
href="vendor/bootstrap-5.3.3-dist/css/bootstrap.min.css"
rel="stylesheet" />
<link href="index.css" rel="stylesheet" />
</head>
<body id="app" class="bg">
<div class="container rounded bg-dark text-light mt-5 p-5">
<header>
<h1>RF Dashboard</h1>
<p><i>Flying to the coder's high...</i></p>
</header>
<hr class="border border-danger border-1 opacity-50" />
<div class="row mb-3">
<div class="col-12">
<div class="input-group">
<input
id="query"
type="text"
class="form-control"
placeholder="Write your query here..."
aria-label="Write your query here..."
aria-describedby="search"
autocomplete="off"
autofocus />
<a class="btn btn-outline-light" id="search" href="#">
Execute Query
</a>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div id="placeholder" class="text-center"></div>
</div>
</div>
<hr class="border border-danger border-1 opacity-50" />
<div class="row">
<div class="col-12">
<div class="text-center">
<button
class="btn btn-small btn-outline-light mb-2"
type="button"
id="toggle-join"
data-bs-toggle="button">
Join: Off
</button>
</div>
<div id="placeholder1" class="text-center"></div>
</div>
</div>
</div>
<script src="vendor/jquery/jquery-3.7.1.min.js"></script>
<script src="vendor/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js"></script>
<script src="index.js"></script>
</body>
</html>
Berikut ini adalah isi dari "index.js":
;(async function () {
$(document).ready(async function () {
// https://chat.openai.com/?q=%5Byour_prompt%5D
// https://en.wikipedia.org/w/index.php?fulltext=1&search=php&title=Special%3ASearch&ns0=1
// https://www.youtube.com/results?search_query=php
// https://www.tokopedia.com/search?st=&q=gelas&srp_component_id=02.01.00.00&srp_page_id=&srp_page_title=&navsource=
localStorage.clear()
let isJoinActive = false
let theTarget = '_self'
const arrGoogleBtn = [
'site:reddit.com',
'site:quora.com',
'site:github.com',
'site:freecodecamp.org',
'site:medium.com',
'site:dev.to',
'site:hackernoon.com',
'site:codeproject.com',
'site:forum.xda-developers.com',
'site:tomshardware.com',
'site:stackoverflow.com',
'site:superuser.com',
'site:serverfault.com',
'site:askubuntu.com',
'site:softwarerecs.stackexchange.com',
'site:android.stackexchange.com',
'site:raspberrypi.stackexchange.com',
'site:freelancing.stackexchange.com',
]
//
if (q('q')) {
location.href = `https://www.google.com/search?q=${q('q')}`
$('#query').val(q('q'))
return
}
//
const doGoogle = function () {
if (!isJoinActive) {
$(this).attr(
'href',
`https://www.google.com/search?q=${$('#query').val()}`
)
return
}
//
let orSyntax = ''
for (let i = 0; i < localStorage.length; i++) {
orSyntax =
orSyntax +
(localStorage.getItem(localStorage.key(i)) === 'true'
? (i === 0 ? ' ' : ' OR ') + localStorage.key(i)
: '')
}
const totalQuery = $('#query').val() + orSyntax
$(this).attr(
'href',
`https://www.google.com/search?q=${totalQuery}`
)
return
}
$(document).on('contextmenu', '#search', doGoogle)
$('#search').click(doGoogle)
//
$(document).on('keypress', function (e) {
if (e.which == 13) {
$('#search').click()
window.open(`https://www.google.com/search?q=${$('#query').val()}`,'_self');
e.preventDefault()
return false
}
})
// Chat GPT
{
$('#placeholder').append(
`<a id="btn-site-srch-chatgpt" class="all-btn btn btn-outline-light mx-2 my-2" href="#">ChatGPT</a>`
)
const doSearch = function () {
const finalQuery = `https://chat.openai.com/?q=${$(
'#query'
).val()}`
$(this).attr('href', finalQuery)
}
$(document).on('contextmenu', '#btn-site-srch-chatgpt', doSearch)
$('#btn-site-srch-chatgpt').click(doSearch)
}
// Wikipedia
{
$('#placeholder').append(
`<a id="btn-site-srch-wikipedia" class="all-btn btn btn-outline-light mx-2 my-2" href="#">Wikipedia</a>`
)
const doSearch = function () {
const finalQuery = `https://en.wikipedia.org/w/index.php?fulltext=1&search=${$(
'#query'
).val()}&title=Special%3ASearch&ns0=1`
$(this).attr('href', finalQuery)
}
$(document).on('contextmenu', '#btn-site-srch-wikipedia', doSearch)
$('#btn-site-srch-wikipedia').click(doSearch)
}
// YouTube
{
$('#placeholder').append(
`<a id="btn-site-srch-youtube" class="all-btn btn btn-outline-light mx-2 my-2" href="#">YouTube</a>`
)
const doSearch = function () {
const finalQuery = `https://www.youtube.com/results?search_query=${$(
'#query'
).val()}`
$(this).attr('href', finalQuery)
}
$(document).on('contextmenu', '#btn-site-srch-youtube', doSearch)
$('#btn-site-srch-youtube').click(doSearch)
}
// Tokopedia
{
$('#placeholder').append(
`<a id="btn-site-srch-tokopedia" class="all-btn btn btn-outline-light mx-2 my-2" href="#">Tokopedia</a>`
)
const doSearch = function () {
const finalQuery = `https://www.tokopedia.com/search?q=${$(
'#query'
).val()}`
$(this).attr('href', finalQuery)
}
$(document).on('contextmenu', '#btn-site-srch-tokopedia', doSearch)
$('#btn-site-srch-tokopedia').click(doSearch)
}
// Joiner
$(`#toggle-join`).click(function () {
isJoinActive = !isJoinActive
$(this).text(isJoinActive === true ? 'Join: On' : 'Join: Off')
$(`.all-btn`).each(function (index) {
$(this).attr(
'data-bs-toggle',
isJoinActive === true ? 'button' : ''
)
})
})
// Google Site
arrGoogleBtn.forEach((item, index) => {
$('#placeholder1').append(
`<a id="btn-site-srch-${index}" class="all-btn btn btn-outline-danger mx-2 my-2" data-bs-toggle="" href="#">${item}</a>`
)
const doSearch = function () {
const isToggleStateActive = isJoinActive
console.log(isToggleStateActive)
if (isToggleStateActive) {
if ($(this).attr('aria-pressed') === 'true') {
localStorage.setItem(item, 'true')
} else {
localStorage.removeItem(item)
}
} else {
const finalQuery = `https://www.google.com/search?q=${$(
'#query'
).val()}+${item}`
$(this).attr('href', finalQuery)
}
}
$(document).on('contextmenu', `#btn-site-srch-${index}`, doSearch)
$(`#btn-site-srch-${index}`).click(doSearch)
})
})
//
function q(variable) {
var query = window.location.search.substring(1)
var vars = query.split('&')
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=')
if (pair[0] == variable) {
return pair[1]
}
}
return null
}
})()
Berikut ini adalah isi dari "index.css":
body,
html {
/* height: 100%; */
margin: 0;
}
.bg {
background-image: url('hypnotize.svg');
height: 100%;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
Berikut ini adalah isi dari "dummy.html":
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Dummy</title>
</head>
<body>
<script src="dummy.js"></script>
</body>
</html>
Berikut ini adalah isi dari "dummy.js":
window.open('index.html', '_self')
Karena aplikasi ini memiliki dependency berupa Bootstrap 5.3.3 dan jQuery 3.7.1, maka downloadlah keduanya, kemudian letakkan di folder project seperti ini:
- bootstrap di "vendor/bootstrap-5.3.3-dist" termasuk css dan js-nya.
- jquery di "vendor/jquery/jquery-3.7.1.min.js"
Perhatikan bahwa folder vendor berada langsung di bawah root folder project ini.
Sebagai gambaran, beginilah struktur vendor setelah jadi:
📦vendor
┣ 📂bootstrap-5.3.3-dist
┃ ┣ 📂css
┃ ┃ ┣ 📜bootstrap-grid.css
┃ ┃ ┣ 📜bootstrap-grid.css.map
┃ ┃ ┣ 📜bootstrap-grid.min.css
┃ ┃ ┣ 📜bootstrap-grid.min.css.map
┃ ┃ ┣ 📜bootstrap-grid.rtl.css
┃ ┃ ┣ 📜bootstrap-grid.rtl.css.map
┃ ┃ ┣ 📜bootstrap-grid.rtl.min.css
┃ ┃ ┣ 📜bootstrap-grid.rtl.min.css.map
┃ ┃ ┣ 📜bootstrap-reboot.css
┃ ┃ ┣ 📜bootstrap-reboot.css.map
┃ ┃ ┣ 📜bootstrap-reboot.min.css
┃ ┃ ┣ 📜bootstrap-reboot.min.css.map
┃ ┃ ┣ 📜bootstrap-reboot.rtl.css
┃ ┃ ┣ 📜bootstrap-reboot.rtl.css.map
┃ ┃ ┣ 📜bootstrap-reboot.rtl.min.css
┃ ┃ ┣ 📜bootstrap-reboot.rtl.min.css.map
┃ ┃ ┣ 📜bootstrap-utilities.css
┃ ┃ ┣ 📜bootstrap-utilities.css.map
┃ ┃ ┣ 📜bootstrap-utilities.min.css
┃ ┃ ┣ 📜bootstrap-utilities.min.css.map
┃ ┃ ┣ 📜bootstrap-utilities.rtl.css
┃ ┃ ┣ 📜bootstrap-utilities.rtl.css.map
┃ ┃ ┣ 📜bootstrap-utilities.rtl.min.css
┃ ┃ ┣ 📜bootstrap-utilities.rtl.min.css.map
┃ ┃ ┣ 📜bootstrap.css
┃ ┃ ┣ 📜bootstrap.css.map
┃ ┃ ┣ 📜bootstrap.min.css
┃ ┃ ┣ 📜bootstrap.min.css.map
┃ ┃ ┣ 📜bootstrap.rtl.css
┃ ┃ ┣ 📜bootstrap.rtl.css.map
┃ ┃ ┣ 📜bootstrap.rtl.min.css
┃ ┃ ┗ 📜bootstrap.rtl.min.css.map
┃ ┗ 📂js
┃ ┃ ┣ 📜bootstrap.bundle.js
┃ ┃ ┣ 📜bootstrap.bundle.js.map
┃ ┃ ┣ 📜bootstrap.bundle.min.js
┃ ┃ ┣ 📜bootstrap.bundle.min.js.map
┃ ┃ ┣ 📜bootstrap.esm.js
┃ ┃ ┣ 📜bootstrap.esm.js.map
┃ ┃ ┣ 📜bootstrap.esm.min.js
┃ ┃ ┣ 📜bootstrap.esm.min.js.map
┃ ┃ ┣ 📜bootstrap.js
┃ ┃ ┣ 📜bootstrap.js.map
┃ ┃ ┣ 📜bootstrap.min.js
┃ ┃ ┗ 📜bootstrap.min.js.map
┗ 📂jquery
┃ ┗ 📜jquery-3.7.1.min.js
Setelah semua itu selesai, Anda harus aktifkan developer mode pada browser Chrome Anda, kemudian memilih folder project ini untuk menginstall extension ini.