diff --git a/public/!!.html b/public/!!.html
index 3e732d38..e8d1ffbe 100644
--- a/public/!!.html
+++ b/public/!!.html
@@ -8,7 +8,7 @@
-
@@ -61,6 +62,7 @@
+ Ctrl + S
@@ -72,7 +74,8 @@
Eruda is loading...
diff --git a/public/assets/css/$.css b/public/assets/css/$.css
index b0e68968..c45279f7 100644
--- a/public/assets/css/$.css
+++ b/public/assets/css/$.css
@@ -222,6 +222,20 @@ body {
color: #818181;
}
+.shortcut-indicator-2 {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(calc(-50% + 300px), -50%);
+ font-size: 12px;
+ font-weight: 500;
+ color: #000000;
+ background-color: #c4c4c4;
+ padding: 2px 6px;
+ border-radius: 7px;
+ cursor: pointer;
+}
+
#lockIcon {
position: absolute;
left: 25px;
@@ -284,7 +298,7 @@ body {
background-size: 35px 35px;
background-position: 10px center;
background-repeat: no-repeat;
- border-radius: 20px;
+ border-radius: 25px;
color: #e0e0e0;
font-size: 16px;
border: 1px solid #ffffff1a;
@@ -304,6 +318,20 @@ body {
color: #ffffff69;
}
+.shortcut-indicator {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(calc(-50% + 235px), -50%);
+ font-size: 12px;
+ font-weight: 500;
+ color: #000000;
+ background-color: #c4c4c4;
+ padding: 2px 6px;
+ border-radius: 7px;
+ cursor: pointer;
+}
+
#erudaLoadingScreen {
position: fixed;
top: 50%;
diff --git a/public/assets/css/a.css b/public/assets/css/a.css
index bd65801b..2dcadc13 100644
--- a/public/assets/css/a.css
+++ b/public/assets/css/a.css
@@ -16,6 +16,7 @@
flex-wrap: wrap;
justify-content: center;
align-items: flex-start;
+ align-content: flex-start;
gap: 20px;
max-width: 80%;
margin: 0 auto;
@@ -35,7 +36,7 @@
cursor: pointer;
user-select: none;
text-align: center;
- border: 2px solid #ffffff21;
+ border: 1px solid #ffffff21;
backdrop-filter: blur(10px);
transition: all 0.3s ease;
width: 180px;
@@ -82,6 +83,7 @@
margin-bottom: 20px;
color: #a8a8a8;
animation: fadeIn 2s ease;
+ position: relative;
}
#appSearchInput {
@@ -102,11 +104,25 @@
transition: all 0.3s ease;
}
+#appSearchInput:focus,
+#appSearchInput:hover {
+ border: 1px solid #ffffff69;
+}
+
#appSearchInput::placeholder {
color: #a8a8a8;
}
-#appSearchInput:focus,
-#appSearchInput:hover {
- border: 1px solid #ffffff69;
+.shortcut-indicator-4 {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(calc(-50% + 195px), -50%);
+ font-size: 12px;
+ font-weight: 500;
+ color: #000000;
+ background-color: #c4c4c4;
+ padding: 2px 6px;
+ border-radius: 7px;
+ cursor: pointer;
}
\ No newline at end of file
diff --git a/public/assets/css/g.css b/public/assets/css/g.css
index 79ebf038..a001407f 100644
--- a/public/assets/css/g.css
+++ b/public/assets/css/g.css
@@ -83,6 +83,7 @@
margin-bottom: 20px;
color: #a8a8a8;
animation: fadeIn 2s ease;
+ position: relative;
}
#gameSearchInput {
@@ -103,11 +104,25 @@
transition: all 0.3s ease;
}
+#gameSearchInput:focus,
+#gameSearchInput:hover {
+ border: 1px solid #ffffff69;
+}
+
#gameSearchInput::placeholder {
color: #a8a8a8;
}
-#gameSearchInput:focus,
-#gameSearchInput:hover {
- border: 1px solid #ffffff69;
+.shortcut-indicator-3 {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(calc(-50% + 195px), -50%);
+ font-size: 12px;
+ font-weight: 500;
+ color: #000000;
+ background-color: #c4c4c4;
+ padding: 2px 6px;
+ border-radius: 7px;
+ cursor: pointer;
}
\ No newline at end of file
diff --git a/public/assets/css/settings.css b/public/assets/css/settings.css
index d64e4aa7..8f53af67 100644
--- a/public/assets/css/settings.css
+++ b/public/assets/css/settings.css
@@ -53,7 +53,7 @@
border: none;
padding: 0;
font-size: 10px;
- color: #868686;
+ color: #888888;
cursor: pointer;
z-index: 1000;
outline: none;
@@ -63,7 +63,7 @@
#close-settings:hover {
transform: rotate(90deg);
- color: #f44336;
+ color: #d3d3d3;
}
#close-settings i {
diff --git a/public/assets/css/toast.css b/public/assets/css/toast.css
index bfdf770e..a4e4d4b3 100644
--- a/public/assets/css/toast.css
+++ b/public/assets/css/toast.css
@@ -84,7 +84,7 @@
.toast .toast-close {
background: none;
border: none;
- color: #868686;
+ color: #888888;
font-size: 18px;
cursor: pointer;
padding: 0;
@@ -93,5 +93,5 @@
}
.toast-close:hover {
- color: #f44336;
+ color: #d3d3d3;
}
\ No newline at end of file
diff --git a/public/assets/js/$.js b/public/assets/js/$.js
index 1b3e12f9..891c05b5 100644
--- a/public/assets/js/$.js
+++ b/public/assets/js/$.js
@@ -8,10 +8,8 @@ document.addEventListener('DOMContentLoaded', () => {
const iframe = document.getElementById('cool-iframe')
const erudaLoadingScreen = document.getElementById('erudaLoadingScreen')
if (!refreshIcon || !fullscreenIcon || !backIcon || !forwardIcon || !iframe) return
-
const originalTitle = document.title
let loadingHidden = false
-
function showLoadingScreen(withToast = true, showEruda = false) {
loadingHidden = false
NProgress.start()
@@ -24,14 +22,12 @@ document.addEventListener('DOMContentLoaded', () => {
)
}
}
-
function hideLoadingScreen() {
if (loadingHidden) return
loadingHidden = true
NProgress.done()
document.title = originalTitle
}
-
refreshIcon.addEventListener('click', () => {
refreshIcon.classList.add('spin')
if (iframe.tagName === 'IFRAME') {
@@ -43,14 +39,12 @@ document.addEventListener('DOMContentLoaded', () => {
}
setTimeout(() => refreshIcon.classList.remove('spin'), 300)
})
-
fullscreenIcon.addEventListener('click', () => {
if (iframe.requestFullscreen) iframe.requestFullscreen()
else if (iframe.mozRequestFullScreen) iframe.mozRequestFullScreen()
else if (iframe.webkitRequestFullscreen) iframe.webkitRequestFullscreen()
else if (iframe.msRequestFullscreen) iframe.msRequestFullscreen()
})
-
backIcon.addEventListener('click', () => {
if (currentIndex > 0) {
currentIndex--
@@ -60,7 +54,6 @@ document.addEventListener('DOMContentLoaded', () => {
updateDecodedSearchInput()
}
})
-
forwardIcon.addEventListener('click', () => {
if (currentIndex < historyStack.length - 1) {
currentIndex++
@@ -70,17 +63,15 @@ document.addEventListener('DOMContentLoaded', () => {
updateDecodedSearchInput()
}
})
-
function normalizeUrl(urlStr) {
try {
const url = new URL(urlStr)
url.searchParams.delete('ia')
return url.toString()
- } catch (e) {
+ } catch {
return urlStr
}
}
-
function addToHistory(url) {
const normalized = normalizeUrl(url)
if (currentIndex >= 0 && normalizeUrl(historyStack[currentIndex]) === normalized) return
@@ -90,14 +81,12 @@ document.addEventListener('DOMContentLoaded', () => {
updateNavButtons()
updateDecodedSearchInput()
}
-
function updateNavButtons() {
backIcon.disabled = currentIndex <= 0
forwardIcon.disabled = currentIndex >= historyStack.length - 1
backIcon.classList.toggle('disabled', currentIndex <= 0)
forwardIcon.classList.toggle('disabled', currentIndex >= historyStack.length - 1)
}
-
function updateDecodedSearchInput() {
const searchInput2 = document.getElementById('searchInputt')
if (!searchInput2) return
@@ -116,7 +105,6 @@ document.addEventListener('DOMContentLoaded', () => {
lockIcon.style.color = ''
}
}
-
iframe.addEventListener('load', () => {
try {
hideLoadingScreen()
@@ -126,18 +114,15 @@ document.addEventListener('DOMContentLoaded', () => {
if (erudaLoadingScreen) erudaLoadingScreen.style.display = 'none'
}
})
-
iframe.addEventListener('error', () => {
hideLoadingScreen()
})
-
iframe.addEventListener('loadstart', () => {
const navBar = document.querySelector('.navbar')
const navbarToggle = document.getElementById('navbar-toggle')
if (navbarToggle && navbarToggle.checked && navBar) navBar.style.display = 'block'
showLoadingScreen(false, false)
})
-
const navBar = document.querySelector('.navbar')
const topBar = document.querySelector('.topbar')
const searchInput1 = document.getElementById('searchInput')
@@ -145,7 +130,6 @@ document.addEventListener('DOMContentLoaded', () => {
const movies = document.getElementById('movies')
const ai = document.getElementById('ai')
const navbarToggle = document.getElementById('navbar-toggle')
-
if (navbarToggle && navBar) {
const savedNavbarState = localStorage.getItem('navbarToggled')
navbarToggle.checked = savedNavbarState === null ? true : savedNavbarState === 'true'
@@ -155,28 +139,27 @@ document.addEventListener('DOMContentLoaded', () => {
navBar.style.display = iframe.style.display === 'block' && navbarToggle.checked ? 'block' : 'none'
})
}
-
iframe.style.display = 'none'
window.addEventListener('load', hideLoadingScreen)
-
- ;
- [searchInput1, searchInput2].forEach(input => {
+ ;[searchInput1, searchInput2].forEach(input => {
if (input) {
input.addEventListener('keyup', e => {
- if (e.key === 'Enter') handleSearch(input.value)
+ if (e.key === 'Enter') {
+ const val = input.value.trim()
+ if (val) handleSearch(val)
+ else showToast('Please enter something in the Search Bar.', 'error', 'warning')
+ }
})
}
})
-
if (movies) movies.addEventListener('click', e => {
- e.preventDefault();
+ e.preventDefault()
handleSearch('https://movies.usewaves.site/')
})
if (ai) ai.addEventListener('click', e => {
- e.preventDefault();
+ e.preventDefault()
handleSearch('https://ai.usewaves.site/')
})
-
function clearBackground() {
const preserved = [
document.querySelector('.navbar'),
@@ -188,8 +171,11 @@ document.addEventListener('DOMContentLoaded', () => {
if (!preserved.includes(child)) child.remove()
})
}
-
async function handleSearch(query) {
+ if (!query || !query.trim()) {
+ showToast('Please enter something in the Search Bar.', 'error', 'warning')
+ return
+ }
clearBackground()
let searchURL
if (
@@ -229,9 +215,7 @@ document.addEventListener('DOMContentLoaded', () => {
hideLoadingScreen()
}
}
-
window.handleSearch = handleSearch
-
function generateSearchUrl(query) {
try {
return new URL(query).toString()
@@ -243,7 +227,6 @@ document.addEventListener('DOMContentLoaded', () => {
}
return `https://duckduckgo.com/?q=${encodeURIComponent(query)}&ia=web`
}
-
function showToast(message, type = 'success', iconType = 'check') {
const toast = document.createElement('div')
toast.className = `toast show ${type}`
@@ -273,7 +256,6 @@ document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => toast.remove(), 500)
}, 3000)
}
-
function preloadResources(url) {
if (!url) return
try {
@@ -285,17 +267,14 @@ document.addEventListener('DOMContentLoaded', () => {
document.head.appendChild(link)
} catch {}
}
-
function getUrl(url) {
return Promise.resolve(__uv$config.prefix + __uv$config.encodeUrl(url))
}
-
function generateSubject() {
const subjects = ['math', 'science', 'history', 'art', 'programming', 'philosophy']
const random = subjects[Math.floor(Math.random() * subjects.length)]
history.replaceState({}, '', '/learning?subject=' + random)
}
-
function decodeUrl(enc) {
try {
const o = new URL(enc, window.location.origin)
@@ -307,7 +286,6 @@ document.addEventListener('DOMContentLoaded', () => {
} catch {}
return enc
}
-
window.decodeUrl = decodeUrl
window.addToHistory = addToHistory
window.updateDecodedSearchInput = updateDecodedSearchInput
diff --git a/public/assets/js/shortcuts.js b/public/assets/js/shortcuts.js
new file mode 100644
index 00000000..919201ee
--- /dev/null
+++ b/public/assets/js/shortcuts.js
@@ -0,0 +1,109 @@
+(function () {
+ document.addEventListener('DOMContentLoaded', function () {
+ function getSearchInputs() {
+ return [
+ document.getElementById('searchInput'),
+ document.getElementById('searchInputt'),
+ document.getElementById('gameSearchInput'),
+ document.getElementById('appSearchInput')
+ ].filter(Boolean);
+ }
+
+ function isVisible(el) {
+ return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
+ }
+
+ function focusFirstVisibleInput() {
+ const inputs = getSearchInputs();
+ for (const input of inputs) {
+ if (isVisible(input)) {
+ input.focus();
+ return;
+ }
+ }
+ if (inputs.length) {
+ inputs[0].focus();
+ }
+ }
+
+ document.addEventListener('keydown', function (e) {
+ if (e.key === 'Escape') {
+ const inputs = getSearchInputs();
+ const active = document.activeElement;
+ if (inputs.includes(active)) {
+ active.blur();
+ e.preventDefault();
+ return;
+ }
+ }
+
+ if (e.ctrlKey && e.key.toLowerCase() === 's') {
+ e.preventDefault();
+ focusFirstVisibleInput();
+ }
+ });
+
+ document.querySelectorAll(
+ '.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4'
+ ).forEach(function (el) {
+ el.addEventListener('click', function (e) {
+ e.preventDefault();
+ focusFirstVisibleInput();
+ });
+ });
+
+ document.body.addEventListener('click', function (e) {
+ if (
+ e.target.classList.contains('shortcut-indicator') ||
+ e.target.classList.contains('shortcut-indicator-2') ||
+ e.target.classList.contains('shortcut-indicator-3') ||
+ e.target.classList.contains('shortcut-indicator-4')
+ ) {
+ e.preventDefault();
+ focusFirstVisibleInput();
+ }
+ });
+
+ const coolIframe = document.getElementById('cool-iframe');
+ if (coolIframe) {
+ coolIframe.addEventListener('load', function () {
+ const doc = coolIframe.contentWindow.document;
+
+ doc.addEventListener('keydown', function (e) {
+ if (e.key === 'Escape') {
+ if (doc.activeElement && doc.activeElement.blur) {
+ doc.activeElement.blur();
+ e.preventDefault();
+ return;
+ }
+ }
+ if (e.ctrlKey && e.key.toLowerCase() === 's') {
+ e.preventDefault();
+ document.dispatchEvent(new KeyboardEvent('keydown', {
+ key: 's',
+ ctrlKey: true
+ }));
+ }
+ });
+
+ doc.querySelectorAll(
+ '.shortcut-indicator, .shortcut-indicator-2, .shortcut-indicator-3, .shortcut-indicator-4'
+ ).forEach(function (iframeEl) {
+ iframeEl.addEventListener('click', function (e) {
+ e.preventDefault();
+ window.parent.postMessage({
+ type: 'iframe-focus-search'
+ }, '*');
+ });
+ });
+ });
+ }
+
+ window.addEventListener('message', function (event) {
+ const msg = event.data;
+ if (msg.type === 'iframe-focus-search') {
+ focusFirstVisibleInput();
+ }
+ });
+ });
+})();
\ No newline at end of file