This commit is contained in:
Hazel Noack
2025-08-01 10:45:26 +02:00
parent a62b445f19
commit 4f44974c58
9 changed files with 65 additions and 333 deletions

View File

@@ -0,0 +1,116 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ .PageTitle }}</title>
<link rel="stylesheet" type="text/css" href="assets/style.css">
</head>
<body>
<form id="search-form" class="search-grid" action="{{ .SearchFormAction }}">
<div class="search-logo">
<img als="girl_juice" src="assets/girl_juice.png" />
<h2 class="phrases"></h2>
<img als="girl_juice" src="assets/girl_juice.png" />
</div>
<input id="search-input" name="{{ .SearchInputName }}" type="text" class="grid-item" class="search" placeholder="{{ .SearchPlaceholder }}" autocomplete="off" />
{{ if eq .ActiveCard "stores" }}
<div class="cards" id="stores">
{{ $T := .DiyHrtTarget }}
{{range $Store := .Stores }}
<a target="{{ $T }}" href="{{ $Store.Url }}" class="card">
<h3>{{ $Store.Name }}</h3>
</a>
{{- end }}
</div>
{{ end }}
{{ if eq .ActiveCard "listings" }}
<div class="cards" id="listings">
{{ $T := .DiyHrtTarget }}
{{range $Listing := .Listings }}
<a target="{{ $T }}" href="{{ $Listing.Url }}" class="card {{ if $Listing.InStock }}in-stock{{ end }}">
<h3>{{ $Listing.ProductName }}</h3>
<p>{{ $Listing.StoreName }} - {{ $Listing.Price }} {{ $Listing.PriceCurrency }}</p>
</a>
{{- end }}
</div>
{{ end }}
{{ if eq .ActiveCard "websites" }}
<div class="cards" id="websites">
{{ $T := .WebsiteTarget }}
{{range $Website := .Websites }}
<a href="{{ $Website.Url }}" class="card" target="{{ $T }}">
<h3>{{ $Website.Name }}</h3>
<img class="card-image" src="{{ $Website.ImageUrl }}" alt="{{ $Website.Name }} picture">
</a>
{{- end }}
</div>
{{ end }}
</form>
<script>
const phrases = [
{{range $Phrase := .HeaderPhrases }}
"{{ $Phrase }}",
{{- end }}
]
function setTitle(element, s, i) {
i++
element.textContent = s.substring(0, i)
if (i >=s.length) return;
setTimeout(() => setTitle(element, s, i), 100);
}
function titleChanger(element) {
setTitle(element, phrases[Math.floor(Math.random()*phrases.length)], 0);
setTimeout(() => titleChanger(element), 10000);
}
Array.from(document.querySelectorAll(".phrases")).forEach(element => {
titleChanger(element);
})
document.addEventListener('DOMContentLoaded', function() {
Array.from(document.querySelectorAll('input')).forEach(element => {
element.focus();
})
});
document.addEventListener('DOMContentLoaded', function() {
const marqueeElement = document.body;
let xPosition = 0;
let yPosition = 0;
const xSpeed = {{ .BackgroundScrollX }}; // Adjust speed here (lower is slower)
const ySpeed = {{ .BackgroundScrollY }};
function animateMarquee() {
xPosition -= xSpeed;
yPosition -= ySpeed;
// Reset position when the image has scrolled completely
if (Math.abs(xPosition) >= marqueeElement.offsetWidth) {
xPosition = 0;
}
if (Math.abs(yPosition) >= marqueeElement.offsetHeight) {
yPosition = 0;
}
marqueeElement.style.backgroundPosition = `${xPosition}px ${yPosition}px`;
requestAnimationFrame(animateMarquee);
}
// Start the animation
animateMarquee();
});
</script>
<script src="scripts/search.js"></script>
</body>
</html>

View File

@@ -0,0 +1,97 @@
console.log("adding features to search...");
const form = document.getElementById("search-form");
const input = document.getElementById("search-input");
// https://stackoverflow.com/a/3809435/16804841
const expression =
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/gi;
const urlRegex = new RegExp(expression);
const searchEngines = {
g: {
action: "https://www.google.com/search",
name: "q",
},
d: {
action: "https://duckduckgo.com/",
name: "q",
},
y: {
action: "https://www.youtube.com/results",
name: "search_query",
},
ya: {
action: "https://yandex.com/search/",
name: "text",
},
lure: {
action: "https://lure.sh/pkgs",
name: "q",
},
};
const translationPrefixes = ["t", "translation"];
function getDeepLUrl(s) {
const parts = s.split("-");
if (parts.length != 3) {
return undefined;
}
return `https://www.deepl.com/en/translator?/#${encodeURIComponent(
parts[0].trim()
)}/${encodeURIComponent(parts[1].trim())}/${encodeURIComponent(
parts[2].trim()
)}`;
}
form.addEventListener("submit", (event) => {
event.preventDefault();
s = input.value;
// check if url
if (s.match(urlRegex)) {
window.open(s, "_self");
return;
}
// deepl translations
let doTranslation = false;
for (const value of translationPrefixes) {
const prefix = `!${value} `;
if (s.startsWith(prefix)) {
doTranslation = true;
s = s.slice(prefix.length); // Remove the !{key} prefix
break;
}
}
if (doTranslation) {
const url = getDeepLUrl(s);
if (url) {
window.open(url.toString(), "_self");
return;
}
}
// Check if the string starts with ! followed by a key from searchEngines
let selectedEngine = {
action: form.getAttribute("action"),
name: input.getAttribute("name"),
};
for (const [key, value] of Object.entries(searchEngines)) {
const prefix = `!${key} `;
if (s.startsWith(prefix)) {
selectedEngine = value;
s = s.slice(prefix.length); // Remove the !{key} prefix
break;
}
}
const url = new URL(selectedEngine.action);
url.searchParams.set(selectedEngine.name, s.trim());
window.open(url.toString(), "_self");
});

View File

@@ -0,0 +1,115 @@
* {
box-sizing: border-box;
}
body {
margin: 0;
height: 100vh;
background-color: pink;
display: flex;
align-items: center;
justify-content: center;
background:
url("bg.svg") center center/auto repeat,
linear-gradient(to bottom, transparent, pink);
}
.search-grid {
width: 100%;
margin-left: 10em;
margin-right: 10em;
display: grid;
gap: 5em;
grid-template-rows: 10em 4em 17em;
}
.search {
width: 100%;
grid-row: 2;
grid-column: 1 / span 2;
}
.search-logo {
grid-row: 1;
height: 100%;
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
color: black;
}
@media (max-height: 300px) {
.search-grid {
grid-template-rows: 4em;
}
.search-logo {
display: none;
}
}
.cards {
height: 100%;
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
gap: 1em;
overflow: auto;
}
.card {
background-color: rgba(255, 255, 255, 0.5);
width: 10em;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
color: black;
gap: 1em;
padding: 1em;
height: 15em;
border-radius: 1em;
}
#listings .card {
background-color: rgba(255, 0, 0, 0.5);
}
#listings .in-stock {
background-color: rgba(125, 255, 125, 0.5);
}
.card h3 {
margin: 0;
}
.card-image {
height: 100%;
aspect-ratio: 1/1;
}
.search-logo img {
height: 100%;
}
.grid-item {
background-color: lightblue;
padding: 1em;
border-radius: 0.5em;
}