Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/functions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
function generateHashkey() {
return (
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15)
);
}
38 changes: 23 additions & 15 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,48 @@

<HEAD>
<Title> Catalyst </Title>
<script src="./functions.js"></script>
<script src="./tabs.js" defer></script>
<script src="./loader.js" defer></script>
<script src="./search.js" defer></script>
<link rel="stylesheet" type="text/css" href="../font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="../styles.css">
<link rel="stylesheet" type="text/css" href="../output/tailwind.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</HEAD>

<BODY class="min-w-full min-h-full dark:bg-black">
<div class="flex items-center px-4 mt-2">
<div class="flex items-center px-4 py-2 mt-2 bg-gray-100">
<div id="tabs-bar" class="flex items-center flex-1 space-x-2 overflow-auto no-scrollbar">
<!-- tabs are inserted with JS -->
</div>
<button id="remove-tab" onClick="removeTab()"
class="text-center p-2 bg-green-300 hover:bg-green-400 transition rounded"><i style="color: black;"
class="fa fa-times-circle"></i></button>
<div class="inline-flex px-1">
<button id="create-tab" onClick="createTab()"
class="rounded-l text-center p-2 bg-red-300 hover:bg-red-400 transition"><i style="color: black;"
class="fa fa-plus"></i></button>
<button id="remove-tab" onClick="removeTab()"
class="text-center p-2 bg-green-300 hover:bg-green-400 transition rounded-r"><i style="color: black;"
class="fa fa-times-circle"></i></button>
</div>

</div>
<div class="w-full min-h-3 p-2 flex justify-center pt-4">
<input id="searchbar" type="text" style="width: 90%" class="min-w-fit bg-gray-100 p-2 rounded-t"
placeholder="Browse a URL" />
<button id="go" onClick="loadWeb()" class="text-center p-2 bg-purple-300 hover:bg-purple-400 transition">Go</button>
<button id="reload" onClick="reload()" class="text-center p-2 bg-red-300 hover:bg-red-400 transition "><i
style="color: black;" class="fa fa-refresh"></i></button>
<button id="back" onClick="backward()" class="text-center p-2 bg-blue-300 hover:bg-blue-400 transition"><i
<button id="back" onClick="backward()" class="text-center p-2 bg-blue-300 hover:bg-blue-400 rounded-l transition"><i
style="color: black;" class="fa fa-backward"></i></button>
<button id="forward" onClick="forward()" class="text-center p-2 bg-green-300 hover:bg-green-400 transition"><i
style="color: black;" class="fa fa-forward"></i></button>
<button id="create-tab" onClick="createTab()"
class="text-center p-2 bg-blue-300 hover:bg-blue-400 transition rounded-r"><i style="color: black;"
class="fa fa-plus"></i></button>
<input id="searchbar" type="text" style="width: 90%" class="min-w-fit bg-gray-100 p-2"
placeholder="Browse the Web" />
<button id="go" onClick="loadURL()" class="text-center p-2 bg-purple-300 hover:bg-purple-400 transition">Go</button>
<button id="reload" onClick="reload()" class="text-center p-2 bg-red-300 hover:bg-red-400 transition rounded-r"><i
style="color: black;" class="fa fa-refresh"></i></button>


</div>
<div class="suggestions-box" id="autocomplete-suggestions">
<!-- suggestions made with js -->
</div>
<div id="webviews"></div>
<!-- <webview style="width: 100vw; height: 95vh;" id="view" src="./welcome.html"></webview> -->
</BODY>

</HTML>
</HTML>
5 changes: 0 additions & 5 deletions src/loader.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
function loadWeb() {
var page = document.getElementById("searchbar").value;
document.querySelector(".current").src = page;
}

function reload() {
document.querySelector(".current").reload();
}
Expand Down
58 changes: 58 additions & 0 deletions src/search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// protocols
const protocols = ["https", "http"];
const removeChildren = (parent) => {
while (parent.lastChild) {
parent.removeChild(parent.lastChild);
}
};
const searchbar = document.getElementById("searchbar");
const suggestionsEl = document.getElementById("autocomplete-suggestions");
searchbar.addEventListener("input", async () => {
if (shouldAutocomplete(searchbar.value)) {
// This is for duckduckgo only, in the future, this may be something else, but I think DDG is fine for now.
const autoCompleteCheck = await fetch(
`https://duckduckgo.com/ac/?q=${searchbar.value}`
);
if (!autoCompleteCheck.ok) return;
const autocomplete = await autoCompleteCheck.json();
removeChildren(suggestionsEl);
for (let index = 0; index < autocomplete.length; index++) {
const suggestionText = autocomplete[index].phrase;
// insert suggestion
let suggestion = document.createElement("button");
let suggestionHash = generateHashkey();
suggestion.innerText = suggestionText;
suggestion.classList.add("suggestion");
suggestion.id = "suggestion-" + suggestionHash;
suggestion.addEventListener("click", () => {
document.getElementById("searchbar").value = suggestionText;
loadURL();
removeChildren(suggestionsEl);
});
suggestionsEl.appendChild(suggestion);
}
} else {
removeChildren(suggestionsEl);
}
});

function loadURL() {
var page = document.getElementById("searchbar").value;
if (shouldAutocomplete(page)) {
document.querySelector(
".current"
).src = `https://duckduckgo.com/?q=${page}`;
} else {
document.querySelector(".current").src = page;
}
removeChildren(suggestionsEl);
}
function shouldAutocomplete(input) {
for (let index = 0; index < protocols.length; index++) {
const protocol = protocols[index];
if (input.startsWith(`${protocol}://`)) {
return false;
}
}
return true;
}
53 changes: 43 additions & 10 deletions src/tabs.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
// Init variables
let activeHash = "0";

let hasFavicon = {};
// Functions

/**
* Creates a new tab
*/
function createTab() {
let tab = document.createElement("div");
let span = document.createElement("span");
// Some parts taken from MystPi/Ninetails on Github. Thank you so much!!!
let randomHash =
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15);
let randomHash = generateHashkey();
tab.classList.add("tab");
tab.id = `tab-${randomHash}`;
tab.onclick = () => {
switchTabs(randomHash);
};
tab.innerText = "New Tab";
span.innerText = "New Tab";
document.getElementById("tabs-bar").appendChild(tab);
let view = document.createElement("webview");
view.id = "view-" + randomHash;
view.classList.add("view");
view.allowpopups = "allowpopups";
view.allowpopups = false;
view.webpreferences = "nativeWindowOpen=true";
view.useragent = "Catalyst"
view.useragent = "Catalyst";
view.src = "./welcome.html"; // will be changed when startpage settings are added
let image = document.createElement("img");
image.width = "16";
image.height = "16";
image.style.border = "0";
tab.appendChild(image);
tab.appendChild(span);
addListeners(view, randomHash);
document.getElementById("webviews").appendChild(view);
switchTabs(randomHash);
Expand All @@ -52,7 +57,6 @@ function switchTabs(tabHash) {
x.style.display = "none";
x.classList.remove("current");
});

document.getElementById("view-" + tabHash).style.display = "flex";
document.getElementById("view-" + tabHash).classList.add("current");
view = document.getElementById("view-" + tabHash);
Expand All @@ -61,15 +65,44 @@ function switchTabs(tabHash) {

function addListeners(view, hash) {
const tab = document.getElementById(`tab-${hash}`);
hasFavicon[hash] = false;
if (!hasFavicon[hash]) {
tab.getElementsByTagName("img")[0].style.display = "none";
} else {
tab.getElementsByTagName("img")[0].style.display = "inline";
}
view.addEventListener("did-stop-loading", () => {
tab.innerText = view.getTitle();
tab.getElementsByTagName("span")[0].innerText = view.getTitle();
tab.classList.remove("animate-pulse");
let viewURL = view.getURL();
if (!viewURL.startsWith("file://")) {
document.getElementById("searchbar").value = viewURL;
}
});
view.addEventListener("did-start-loading", () => {
tab.classList.add("animate-pulse");
tab.getElementsByTagName("img")[0].style.display = "none";
});
view.addEventListener("page-title-updated", (e) => {
tab.innerText = e.title;
tab.getElementsByTagName("span")[0].innerText = e.title;
let viewURL = view.getURL();
if (!viewURL.startsWith("file://")) {
document.getElementById("searchbar").value = viewURL;
}
});
view.addEventListener("page-favicon-updated", (e) => {
if (e.favicons.length > 0) {
hasFavicon[hash] = true;
let icon = e.favicons[0];
let img = tab.getElementsByTagName("img")[0];
img.style.display = "inline";
tab.getElementsByTagName("span")[0].classList.add("px-2");
img.src = icon;
} else {
hasFavicon[hash] = false;
tab.getElementsByTagName("span")[0].classList.remove("px-2");
tab.getElementsByTagName("img")[0].style.display = "none";
}
});
}

Expand Down
13 changes: 11 additions & 2 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,19 @@
@apply transition flex items-center flex-1 max-w-md p-2 overflow-hidden text-sm text-gray-600 bg-emerald-100 rounded cursor-pointer whitespace-nowrap;
}
.active-tab {
@apply transition flex items-center flex-1 max-w-md p-2 overflow-hidden text-sm text-white bg-emerald-500 rounded cursor-default whitespace-nowrap font-bold;
@apply transition flex items-center flex-1 max-w-md p-3 overflow-hidden text-sm text-white bg-emerald-500 rounded cursor-default whitespace-nowrap font-bold;
}
.view {
@apply w-[100vw] h-[100vh];
@apply min-w-[100vw] min-h-[100vh];
}
.suggestion {
@apply w-screen border-solid p-2 border-blue-500;
}
.suggestions-box {
@apply absolute rounded-xl bg-red-200 border-blue-500;
}
*:focus {
@apply outline-emerald-600;
}
}

Expand Down