added dynamic lloading for images
This commit is contained in:
parent
8f3f1e2d3e
commit
78c8fdbb4a
3 changed files with 211 additions and 133 deletions
|
@ -1357,10 +1357,10 @@ p {
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background-color: var(--html-bg);
|
background-color: var(--search-bg);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 15px;
|
border-radius: 5px;
|
||||||
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
box-shadow: 0 0 10px var(--box-shadow);
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
width: auto;
|
width: auto;
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
|
@ -1370,9 +1370,9 @@ p {
|
||||||
|
|
||||||
/* Map container */
|
/* Map container */
|
||||||
#map {
|
#map {
|
||||||
height: calc(100% - 60px); /* Adjust this value based on the header height */
|
height: calc(100% - 60px);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
top: 60px; /* Same value as in the results-search-container margin-top */
|
top: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Leaflet control buttons */
|
/* Leaflet control buttons */
|
||||||
|
@ -1465,86 +1465,22 @@ p {
|
||||||
text-shadow: 1px 1px 2px var(--border) !important; /* Adjust text shadow */
|
text-shadow: 1px 1px 2px var(--border) !important; /* Adjust text shadow */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensuring dark theme compliance */
|
.message-bottom-left {
|
||||||
@media (prefers-color-scheme: dark) {
|
display: none;
|
||||||
.leaflet-control-locate,
|
align-items: center;
|
||||||
.leaflet-control-layers-toggle,
|
justify-content: center;
|
||||||
.leaflet-bar a,
|
position: fixed;
|
||||||
.leaflet-bar a:hover,
|
bottom: 20px;
|
||||||
.leaflet-popup-content-wrapper,
|
right: 20px;
|
||||||
.leaflet-popup-tip,
|
background-color: var(--search-bg);
|
||||||
.leaflet-control-attribution,
|
color: var(--text-color);
|
||||||
.leaflet-control-scale,
|
padding: 10px;
|
||||||
.leaflet-control-scale-line {
|
border-radius: 5px;
|
||||||
background-color: var(--button) !important;
|
z-index: 1000;
|
||||||
border: 1px solid var(--border) !important;
|
text-align: center;
|
||||||
color: var(--fg) !important;
|
flex-direction: column;
|
||||||
text-shadow: 1px 1px 2px var(--background-color) !important; /* Dark theme shadow adjustment */
|
border: 1px solid var(--border);
|
||||||
}
|
box-shadow: 0 0 10px var(--box-shadow);
|
||||||
|
|
||||||
.leaflet-control-attribution a {
|
|
||||||
color: var(--link) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --- */
|
|
||||||
|
|
||||||
/* Variables for light theme */
|
|
||||||
:root {
|
|
||||||
--background-color: #ffffff;
|
|
||||||
--text-color: #000000;
|
|
||||||
--highlight: #007bff;
|
|
||||||
--border-color: #dddddd;
|
|
||||||
--search-bg: #f1f3f4;
|
|
||||||
--search-bg-input: #ffffff;
|
|
||||||
--search-bg-input-border: #dfe1e5;
|
|
||||||
--button: #f8f9fa;
|
|
||||||
--link: #1a0dab;
|
|
||||||
--fg: #202124;
|
|
||||||
--html-bg: #ffffff;
|
|
||||||
--snip-border: #dfe1e5;
|
|
||||||
--snip-background: #ffffff;
|
|
||||||
--image-view: #ffffff;
|
|
||||||
--image-view-titlebar: #f1f3f4;
|
|
||||||
--search-button: #5f6368;
|
|
||||||
--image-select: #e8f0fe;
|
|
||||||
--view-image-color: #f8f9fa;
|
|
||||||
--footer-bg: #f2f2f2;
|
|
||||||
--footer-font: #70757a;
|
|
||||||
--border: #e0e0e0;
|
|
||||||
--link-visited: #660099;
|
|
||||||
--publish-info: #70757a;
|
|
||||||
--green: #3c802c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Styles for dark theme */
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
--background-color: #202124;
|
|
||||||
--text-color: #e8eaed;
|
|
||||||
--highlight: #8ab4f8;
|
|
||||||
--border-color: #5f6368;
|
|
||||||
--search-bg: #303134;
|
|
||||||
--search-bg-input: #202124;
|
|
||||||
--search-bg-input-border: #5f6368;
|
|
||||||
--button: #3c4043;
|
|
||||||
--link: #8ab4f8;
|
|
||||||
--fg: #e8eaed;
|
|
||||||
--html-bg: #202124;
|
|
||||||
--snip-border: #5f6368;
|
|
||||||
--snip-background: #303134;
|
|
||||||
--image-view: #202124;
|
|
||||||
--image-view-titlebar: #303134;
|
|
||||||
--search-button: #e8eaed;
|
|
||||||
--image-select: #5f6368;
|
|
||||||
--view-image-color: #202124;
|
|
||||||
--footer-bg: #303134;
|
|
||||||
--footer-font: #e8eaed;
|
|
||||||
--border: #5f6368;
|
|
||||||
--link-visited: #c79fff;
|
|
||||||
--publish-info: #e8eaed;
|
|
||||||
--green: #8ab4f8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body, h1, p, a, input, button {
|
body, h1, p, a, input, button {
|
||||||
|
@ -1889,3 +1825,87 @@ body, h1, p, a, input, button {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- */
|
||||||
|
|
||||||
|
/* Ensuring dark theme compliance */
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.leaflet-control-locate,
|
||||||
|
.leaflet-control-layers-toggle,
|
||||||
|
.leaflet-bar a,
|
||||||
|
.leaflet-bar a:hover,
|
||||||
|
.leaflet-popup-content-wrapper,
|
||||||
|
.leaflet-popup-tip,
|
||||||
|
.leaflet-control-attribution,
|
||||||
|
.leaflet-control-scale,
|
||||||
|
.leaflet-control-scale-line {
|
||||||
|
background-color: var(--button) !important;
|
||||||
|
border: 1px solid var(--border) !important;
|
||||||
|
color: var(--fg) !important;
|
||||||
|
text-shadow: 1px 1px 2px var(--background-color) !important; /* Dark theme shadow adjustment */
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-control-attribution a {
|
||||||
|
color: var(--link) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Variables for light theme */
|
||||||
|
:root {
|
||||||
|
--background-color: #ffffff;
|
||||||
|
--text-color: #000000;
|
||||||
|
--highlight: #007bff;
|
||||||
|
--border-color: #dddddd;
|
||||||
|
--search-bg: #f1f3f4;
|
||||||
|
--search-bg-input: #ffffff;
|
||||||
|
--search-bg-input-border: #dfe1e5;
|
||||||
|
--button: #f8f9fa;
|
||||||
|
--link: #1a0dab;
|
||||||
|
--fg: #202124;
|
||||||
|
--html-bg: #ffffff;
|
||||||
|
--snip-border: #dfe1e5;
|
||||||
|
--snip-background: #ffffff;
|
||||||
|
--image-view: #ffffff;
|
||||||
|
--image-view-titlebar: #f1f3f4;
|
||||||
|
--search-button: #5f6368;
|
||||||
|
--image-select: #e8f0fe;
|
||||||
|
--view-image-color: #f8f9fa;
|
||||||
|
--footer-bg: #f2f2f2;
|
||||||
|
--footer-font: #70757a;
|
||||||
|
--border: #e0e0e0;
|
||||||
|
--link-visited: #660099;
|
||||||
|
--publish-info: #70757a;
|
||||||
|
--green: #3c802c;
|
||||||
|
--box-shadow: #00000020;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Styles for dark theme */
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--background-color: #202124;
|
||||||
|
--text-color: #e8eaed;
|
||||||
|
--highlight: #8ab4f8;
|
||||||
|
--border-color: #5f6368;
|
||||||
|
--search-bg: #303134;
|
||||||
|
--search-bg-input: #202124;
|
||||||
|
--search-bg-input-border: #5f6368;
|
||||||
|
--button: #3c4043;
|
||||||
|
--link: #8ab4f8;
|
||||||
|
--fg: #e8eaed;
|
||||||
|
--html-bg: #202124;
|
||||||
|
--snip-border: #5f6368;
|
||||||
|
--snip-background: #303134;
|
||||||
|
--image-view: #202124;
|
||||||
|
--image-view-titlebar: #303134;
|
||||||
|
--search-button: #e8eaed;
|
||||||
|
--image-select: #5f6368;
|
||||||
|
--view-image-color: #202124;
|
||||||
|
--footer-bg: #303134;
|
||||||
|
--footer-font: #e8eaed;
|
||||||
|
--border: #5f6368;
|
||||||
|
--link-visited: #c79fff;
|
||||||
|
--publish-info: #e8eaed;
|
||||||
|
--green: #8ab4f8;
|
||||||
|
--box-shadow: #ffffff20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -43,7 +43,6 @@
|
||||||
<button name="t" value="file" class="clickable">Torrents</button>
|
<button name="t" value="file" class="clickable">Torrents</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
<form class="results_settings" action="/search" method="get">
|
<form class="results_settings" action="/search" method="get">
|
||||||
<input type="hidden" name="q" value="{{ .Query }}">
|
<input type="hidden" name="q" value="{{ .Query }}">
|
||||||
|
@ -58,27 +57,10 @@
|
||||||
</select>
|
</select>
|
||||||
<button class="results-save" name="t" value="image">Apply settings</button>
|
<button class="results-save" name="t" value="image">Apply settings</button>
|
||||||
</form>
|
</form>
|
||||||
<div class="search-results">
|
<div class="search-results" id="results">
|
||||||
<!-- Results go here -->
|
<!-- Results go here -->
|
||||||
{{ if .Results }}
|
{{ if .Results }}
|
||||||
<div class="images images_viewer_hidden">
|
<div class="images images_viewer_hidden">
|
||||||
<!-- Image Viewer Placeholder - Adapt as necessary -->
|
|
||||||
<div class="image_view image_hide">
|
|
||||||
<!-- Navigation and Close for the Image Viewer -->
|
|
||||||
<!-- Placeholder for dynamic interaction, adapt the onclick functionality as needed -->
|
|
||||||
<div class="image-view-close">
|
|
||||||
<button class="btn-nostyle"><div class="material-icons-round icon_visibility clickable">navigate_before</div></button>
|
|
||||||
<button class="btn-nostyle"><div class="material-icons-round icon_visibility clickable">navigate_next</div></button>
|
|
||||||
<button class="btn-nostyle"><div class="material-icons-round icon_visibility clickable">close</div></button>
|
|
||||||
</div>
|
|
||||||
<!-- Placeholder for selected image -->
|
|
||||||
<a class="image-viewer-link clickable" href="#">
|
|
||||||
<div class="view-image">
|
|
||||||
<img class="view-image-img" src="" alt="Selected Image"/>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<!-- Additional image details here -->
|
|
||||||
</div>
|
|
||||||
<!-- Images Grid -->
|
<!-- Images Grid -->
|
||||||
{{ range .Results }}
|
{{ range .Results }}
|
||||||
<div class="image">
|
<div class="image">
|
||||||
|
@ -93,7 +75,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
<!-- Pagination -->
|
<noscript>
|
||||||
<div class="prev-next prev-img">
|
<div class="prev-next prev-img">
|
||||||
<form action="/search" method="get">
|
<form action="/search" method="get">
|
||||||
<input type="hidden" name="q" value="{{ .Query }}">
|
<input type="hidden" name="q" value="{{ .Query }}">
|
||||||
|
@ -108,14 +90,75 @@
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{{ else }}
|
</noscript>
|
||||||
|
{{ else if .NoResults }}
|
||||||
<div class="no-results">No results found for '{{ .Query }}'. Try different keywords.</div>
|
<div class="no-results">No results found for '{{ .Query }}'. Try different keywords.</div>
|
||||||
|
{{ else }}
|
||||||
|
<div class="no-more-results">Looks like this is the end of results.</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="message-bottom-left" id="message-bottom-left">
|
||||||
|
<span>Searching for new results...</span>
|
||||||
|
</div>
|
||||||
<script>
|
<script>
|
||||||
// Check if JavaScript is enabled and modify the DOM accordingly
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
document.getElementById('content').classList.remove('js-enabled');
|
let page = {{ .Page }};
|
||||||
|
const query = "{{ .Query }}";
|
||||||
|
let loading = false;
|
||||||
|
let hasMoreResults = true;
|
||||||
|
const loadingIndicator = document.getElementById('message-bottom-left');
|
||||||
|
let loadingTimeout;
|
||||||
|
|
||||||
|
function loadResults(newPage) {
|
||||||
|
if (loading || !hasMoreResults) return;
|
||||||
|
loading = true;
|
||||||
|
|
||||||
|
// Show loading indicator if taking more than 100ms
|
||||||
|
loadingTimeout = setTimeout(() => {
|
||||||
|
loadingIndicator.style.display = 'flex';
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
fetch(`/search?q=${encodeURIComponent(query)}&t=image&p=${newPage}`)
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Network response was not ok');
|
||||||
|
}
|
||||||
|
return response.text();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
clearTimeout(loadingTimeout);
|
||||||
|
loadingIndicator.style.display = 'none';
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const doc = parser.parseFromString(data, 'text/html');
|
||||||
|
const newResults = doc.getElementById('results').innerHTML;
|
||||||
|
const noResultsMessage = "No results found for '{{ .Query }}'. Try different keywords.";
|
||||||
|
const endOfResultsMessage = "Looks like this is the end of results.";
|
||||||
|
const serverError = "Internal Server Error";
|
||||||
|
|
||||||
|
if (newResults.includes(noResultsMessage) || newResults.includes(endOfResultsMessage) || newResults.includes(serverError)) {
|
||||||
|
document.getElementById('results').innerHTML += newResults;
|
||||||
|
hasMoreResults = false;
|
||||||
|
} else {
|
||||||
|
document.getElementById('results').innerHTML += newResults;
|
||||||
|
page = newPage;
|
||||||
|
}
|
||||||
|
loading = false;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
clearTimeout(loadingTimeout);
|
||||||
|
loadingIndicator.style.display = 'none';
|
||||||
|
console.error('Error loading results:', error);
|
||||||
|
hasMoreResults = false; // Stop further attempts
|
||||||
|
loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('scroll', () => {
|
||||||
|
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
|
||||||
|
loadResults(page + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -73,6 +73,9 @@
|
||||||
<div class="no-more-results">Looks like this is the end of results.</div>
|
<div class="no-more-results">Looks like this is the end of results.</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="message-bottom-left" id="message-bottom-left">
|
||||||
|
<span>Searching for new results...</span>
|
||||||
|
</div>
|
||||||
<div class="prev-next prev-img" id="prev-next">
|
<div class="prev-next prev-img" id="prev-next">
|
||||||
<form action="/search" method="get">
|
<form action="/search" method="get">
|
||||||
<input type="hidden" name="q" value="{{ .Query }}">
|
<input type="hidden" name="q" value="{{ .Query }}">
|
||||||
|
@ -94,13 +97,23 @@
|
||||||
const query = "{{ .Query }}";
|
const query = "{{ .Query }}";
|
||||||
let loading = false;
|
let loading = false;
|
||||||
let hasMoreResults = true;
|
let hasMoreResults = true;
|
||||||
|
const loadingIndicator = document.getElementById('message-bottom-left');
|
||||||
|
let loadingTimeout;
|
||||||
|
|
||||||
function loadResults(newPage) {
|
function loadResults(newPage) {
|
||||||
if (loading || !hasMoreResults) return;
|
if (loading || !hasMoreResults) return;
|
||||||
loading = true;
|
loading = true;
|
||||||
|
|
||||||
|
// Show loading indicator if taking more than 100ms
|
||||||
|
loadingTimeout = setTimeout(() => {
|
||||||
|
loadingIndicator.style.display = 'flex';
|
||||||
|
}, 100);
|
||||||
|
|
||||||
fetch(`/search?q=${encodeURIComponent(query)}&t=text&p=${newPage}`)
|
fetch(`/search?q=${encodeURIComponent(query)}&t=text&p=${newPage}`)
|
||||||
.then(response => response.text())
|
.then(response => response.text())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
|
clearTimeout(loadingTimeout);
|
||||||
|
loadingIndicator.style.display = 'none';
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
const doc = parser.parseFromString(data, 'text/html');
|
const doc = parser.parseFromString(data, 'text/html');
|
||||||
const newResults = doc.getElementById('results').innerHTML;
|
const newResults = doc.getElementById('results').innerHTML;
|
||||||
|
@ -116,6 +129,8 @@
|
||||||
loading = false;
|
loading = false;
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
clearTimeout(loadingTimeout);
|
||||||
|
loadingIndicator.style.display = 'none';
|
||||||
console.error('Error loading results:', error);
|
console.error('Error loading results:', error);
|
||||||
loading = false;
|
loading = false;
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue