|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>NeonSearch - Futuristic Google Scraper</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script> |
|
|
<style> |
|
|
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Rajdhani:wght@300;500;700&display=swap'); |
|
|
|
|
|
:root { |
|
|
--neon-blue: #00f3ff; |
|
|
--neon-pink: #ff00ff; |
|
|
--neon-purple: #9d00ff; |
|
|
--dark-bg: #0a0a12; |
|
|
--darker-bg: #050508; |
|
|
--card-bg: #12121a; |
|
|
} |
|
|
|
|
|
body { |
|
|
font-family: 'Rajdhani', sans-serif; |
|
|
background-color: var(--dark-bg); |
|
|
color: #e0e0e0; |
|
|
min-height: 100vh; |
|
|
} |
|
|
|
|
|
h1, h2, h3 { |
|
|
font-family: 'Orbitron', sans-serif; |
|
|
} |
|
|
|
|
|
.neon-text { |
|
|
text-shadow: 0 0 5px var(--neon-blue), 0 0 10px var(--neon-blue); |
|
|
color: var(--neon-blue); |
|
|
} |
|
|
|
|
|
.neon-pink { |
|
|
text-shadow: 0 0 5px var(--neon-pink), 0 0 10px var(--neon-pink); |
|
|
color: var(--neon-pink); |
|
|
} |
|
|
|
|
|
.neon-purple { |
|
|
text-shadow: 0 0 5px var(--neon-purple), 0 0 10px var(--neon-purple); |
|
|
color: var(--neon-purple); |
|
|
} |
|
|
|
|
|
.search-input { |
|
|
background-color: var(--card-bg); |
|
|
border: 1px solid #2a2a3a; |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
|
|
|
.search-input:focus { |
|
|
border-color: var(--neon-blue); |
|
|
box-shadow: 0 0 10px rgba(0, 243, 255, 0.5); |
|
|
} |
|
|
|
|
|
.search-btn { |
|
|
background: linear-gradient(45deg, var(--neon-purple), var(--neon-blue)); |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
|
|
|
.search-btn:hover { |
|
|
box-shadow: 0 0 15px rgba(0, 243, 255, 0.7); |
|
|
transform: translateY(-2px); |
|
|
} |
|
|
|
|
|
.result-card { |
|
|
background-color: var(--card-bg); |
|
|
border-left: 3px solid var(--neon-blue); |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
|
|
|
.result-card:hover { |
|
|
transform: translateY(-5px); |
|
|
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3); |
|
|
border-left: 3px solid var(--neon-pink); |
|
|
} |
|
|
|
|
|
.pagination-btn { |
|
|
background-color: var(--card-bg); |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
|
|
|
.pagination-btn:hover { |
|
|
background-color: var(--neon-purple); |
|
|
color: white; |
|
|
} |
|
|
|
|
|
.active-page { |
|
|
background-color: var(--neon-blue); |
|
|
color: white; |
|
|
} |
|
|
|
|
|
.glow { |
|
|
animation: glow 2s infinite alternate; |
|
|
} |
|
|
|
|
|
@keyframes glow { |
|
|
from { |
|
|
box-shadow: 0 0 5px var(--neon-blue); |
|
|
} |
|
|
to { |
|
|
box-shadow: 0 0 20px var(--neon-blue); |
|
|
} |
|
|
} |
|
|
|
|
|
.loading-dots::after { |
|
|
content: '.'; |
|
|
animation: dots 1.5s steps(5, end) infinite; |
|
|
} |
|
|
|
|
|
@keyframes dots { |
|
|
0%, 20% { |
|
|
color: rgba(0,0,0,0); |
|
|
text-shadow: .25em 0 0 rgba(0,0,0,0), .5em 0 0 rgba(0,0,0,0); |
|
|
} |
|
|
40% { |
|
|
color: var(--neon-blue); |
|
|
text-shadow: .25em 0 0 rgba(0,0,0,0), .5em 0 0 rgba(0,0,0,0); |
|
|
} |
|
|
60% { |
|
|
text-shadow: .25em 0 0 var(--neon-blue), .5em 0 0 rgba(0,0,0,0); |
|
|
} |
|
|
80%, 100% { |
|
|
text-shadow: .25em 0 0 var(--neon-blue), .5em 0 0 var(--neon-blue); |
|
|
} |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gray-900"> |
|
|
<div class="container mx-auto px-4 py-8"> |
|
|
|
|
|
<header class="text-center mb-12"> |
|
|
<h1 class="text-5xl font-bold neon-text mb-4">Neon<span class="neon-pink">Search</span></h1> |
|
|
<p class="text-xl text-gray-400">The future of search is here</p> |
|
|
<div class="w-24 h-1 bg-gradient-to-r from-purple-600 to-blue-500 mx-auto mt-4 rounded-full glow"></div> |
|
|
</header> |
|
|
|
|
|
|
|
|
<div class="max-w-3xl mx-auto mb-16"> |
|
|
<form id="searchForm" class="flex flex-col md:flex-row gap-4"> |
|
|
<input |
|
|
type="text" |
|
|
id="searchQuery" |
|
|
placeholder="Enter your search query..." |
|
|
class="flex-grow px-6 py-4 rounded-lg search-input text-white focus:outline-none focus:ring-2 focus:ring-blue-500" |
|
|
required |
|
|
> |
|
|
<button |
|
|
type="submit" |
|
|
class="px-8 py-4 rounded-lg text-white font-bold uppercase tracking-wider search-btn flex items-center justify-center" |
|
|
> |
|
|
<i class="fas fa-search mr-2"></i> Search |
|
|
</button> |
|
|
</form> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="resultsSection" class="hidden"> |
|
|
<div class="flex justify-between items-center mb-6"> |
|
|
<h2 class="text-2xl font-bold neon-text">Search Results</h2> |
|
|
<div id="resultCount" class="text-gray-400"></div> |
|
|
</div> |
|
|
|
|
|
<div id="searchResults" class="space-y-6 mb-8"></div> |
|
|
|
|
|
|
|
|
<div id="pagination" class="flex justify-center gap-2 mt-8"></div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="loadingIndicator" class="hidden text-center py-12"> |
|
|
<div class="inline-block text-4xl neon-text loading-dots">Processing</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="errorMessage" class="hidden text-center py-12"> |
|
|
<div class="inline-block text-2xl neon-pink"> |
|
|
<i class="fas fa-exclamation-triangle mr-2"></i> |
|
|
<span id="errorText">An error occurred</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<footer class="bg-gray-800 py-6 mt-12"> |
|
|
<div class="container mx-auto px-4 text-center text-gray-400"> |
|
|
<p>Powered by Google Custom Search JSON API</p> |
|
|
<p class="mt-2 text-sm">© 2023 NeonSearch - All rights reserved</p> |
|
|
</div> |
|
|
</footer> |
|
|
|
|
|
<script> |
|
|
const API_KEY = 'AIzaSyC1fp0n6L7A77Al5-ANoWHeXKtnJp8-bEs'; |
|
|
const CSE_ID = '919fdda0dd9034703'; |
|
|
let currentPage = 1; |
|
|
let currentQuery = ''; |
|
|
let totalResults = 0; |
|
|
const resultsPerPage = 10; |
|
|
|
|
|
document.getElementById('searchForm').addEventListener('submit', function(e) { |
|
|
e.preventDefault(); |
|
|
currentQuery = document.getElementById('searchQuery').value.trim(); |
|
|
if (currentQuery) { |
|
|
currentPage = 1; |
|
|
searchGoogle(currentQuery, currentPage); |
|
|
} |
|
|
}); |
|
|
|
|
|
function searchGoogle(query, page) { |
|
|
|
|
|
document.getElementById('loadingIndicator').classList.remove('hidden'); |
|
|
document.getElementById('resultsSection').classList.add('hidden'); |
|
|
document.getElementById('errorMessage').classList.add('hidden'); |
|
|
|
|
|
const startIndex = (page - 1) * resultsPerPage + 1; |
|
|
const url = `https://www.googleapis.com/customsearch/v1?q=${encodeURIComponent(query)}&key=${API_KEY}&cx=${CSE_ID}&start=${startIndex}`; |
|
|
|
|
|
fetch(url) |
|
|
.then(response => { |
|
|
if (!response.ok) { |
|
|
throw new Error('Network response was not ok'); |
|
|
} |
|
|
return response.json(); |
|
|
}) |
|
|
.then(data => { |
|
|
if (data.error) { |
|
|
throw new Error(data.error.message || 'API error occurred'); |
|
|
} |
|
|
|
|
|
totalResults = parseInt(data.searchInformation.totalResults) || 0; |
|
|
displayResults(data.items || []); |
|
|
updatePagination(); |
|
|
|
|
|
|
|
|
document.getElementById('loadingIndicator').classList.add('hidden'); |
|
|
document.getElementById('resultsSection').classList.remove('hidden'); |
|
|
}) |
|
|
.catch(error => { |
|
|
console.error('Error:', error); |
|
|
document.getElementById('loadingIndicator').classList.add('hidden'); |
|
|
document.getElementById('errorMessage').classList.remove('hidden'); |
|
|
document.getElementById('errorText').textContent = error.message || 'Failed to fetch results'; |
|
|
}); |
|
|
} |
|
|
|
|
|
function displayResults(items) { |
|
|
const resultsContainer = document.getElementById('searchResults'); |
|
|
const resultCountElement = document.getElementById('resultCount'); |
|
|
|
|
|
resultsContainer.innerHTML = ''; |
|
|
|
|
|
if (items.length === 0) { |
|
|
resultsContainer.innerHTML = ` |
|
|
<div class="text-center py-12 text-gray-400"> |
|
|
<i class="fas fa-search-minus text-4xl mb-4"></i> |
|
|
<p class="text-xl">No results found for your query</p> |
|
|
</div> |
|
|
`; |
|
|
resultCountElement.textContent = '0 results'; |
|
|
return; |
|
|
} |
|
|
|
|
|
resultCountElement.textContent = `${totalResults.toLocaleString()} results`; |
|
|
|
|
|
items.forEach(item => { |
|
|
const resultElement = document.createElement('div'); |
|
|
resultElement.className = 'result-card p-6 rounded-lg hover:shadow-lg'; |
|
|
|
|
|
const title = item.title || 'No title'; |
|
|
const link = item.link || '#'; |
|
|
const snippet = item.snippet || 'No description available.'; |
|
|
const displayLink = new URL(link).hostname.replace('www.', ''); |
|
|
|
|
|
resultElement.innerHTML = ` |
|
|
<h3 class="text-xl font-bold mb-2"> |
|
|
<a href="${link}" class="text-blue-400 hover:text-blue-300 hover:underline" target="_blank" rel="noopener">${title}</a> |
|
|
</h3> |
|
|
<div class="text-green-400 text-sm mb-2">${displayLink}</div> |
|
|
<p class="text-gray-300">${snippet}</p> |
|
|
`; |
|
|
|
|
|
resultsContainer.appendChild(resultElement); |
|
|
}); |
|
|
} |
|
|
|
|
|
function updatePagination() { |
|
|
const paginationContainer = document.getElementById('pagination'); |
|
|
paginationContainer.innerHTML = ''; |
|
|
|
|
|
if (totalResults <= resultsPerPage) return; |
|
|
|
|
|
const totalPages = Math.ceil(totalResults / resultsPerPage); |
|
|
const maxVisiblePages = 5; |
|
|
let startPage, endPage; |
|
|
|
|
|
if (totalPages <= maxVisiblePages) { |
|
|
startPage = 1; |
|
|
endPage = totalPages; |
|
|
} else { |
|
|
const halfVisible = Math.floor(maxVisiblePages / 2); |
|
|
if (currentPage <= halfVisible + 1) { |
|
|
startPage = 1; |
|
|
endPage = maxVisiblePages; |
|
|
} else if (currentPage >= totalPages - halfVisible) { |
|
|
startPage = totalPages - maxVisiblePages + 1; |
|
|
endPage = totalPages; |
|
|
} else { |
|
|
startPage = currentPage - halfVisible; |
|
|
endPage = currentPage + halfVisible; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (currentPage > 1) { |
|
|
const prevButton = document.createElement('button'); |
|
|
prevButton.className = 'px-4 py-2 rounded-lg pagination-btn'; |
|
|
prevButton.innerHTML = '<i class="fas fa-chevron-left mr-1"></i> Prev'; |
|
|
prevButton.addEventListener('click', () => { |
|
|
currentPage--; |
|
|
searchGoogle(currentQuery, currentPage); |
|
|
window.scrollTo({ top: 0, behavior: 'smooth' }); |
|
|
}); |
|
|
paginationContainer.appendChild(prevButton); |
|
|
} |
|
|
|
|
|
|
|
|
for (let i = startPage; i <= endPage; i++) { |
|
|
const pageButton = document.createElement('button'); |
|
|
pageButton.className = `px-4 py-2 rounded-lg pagination-btn ${i === currentPage ? 'active-page' : ''}`; |
|
|
pageButton.textContent = i; |
|
|
pageButton.addEventListener('click', () => { |
|
|
currentPage = i; |
|
|
searchGoogle(currentQuery, currentPage); |
|
|
window.scrollTo({ top: 0, behavior: 'smooth' }); |
|
|
}); |
|
|
paginationContainer.appendChild(pageButton); |
|
|
} |
|
|
|
|
|
|
|
|
if (currentPage < totalPages) { |
|
|
const nextButton = document.createElement('button'); |
|
|
nextButton.className = 'px-4 py-2 rounded-lg pagination-btn'; |
|
|
nextButton.innerHTML = 'Next <i class="fas fa-chevron-right ml-1"></i>'; |
|
|
nextButton.addEventListener('click', () => { |
|
|
currentPage++; |
|
|
searchGoogle(currentQuery, currentPage); |
|
|
window.scrollTo({ top: 0, behavior: 'smooth' }); |
|
|
}); |
|
|
paginationContainer.appendChild(nextButton); |
|
|
} |
|
|
} |
|
|
</script> |
|
|
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=flitrx/ns" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
|
</html> |