mirror of
https://github.com/searxng/searxng.git
synced 2026-09-23 06:36:12 +00:00
[mod] theme: improve thumbnails display on results page
Deletes thumbnails instead of showing an error image and also moves them to the right side. Also gives them a background and makes them into rounded 4:3 rectangles for better ui.
This commit is contained in:
@@ -5,6 +5,7 @@ import { listen, mutable, settings } from "../toolkit.ts";
|
|||||||
import { assertElement } from "../util/assertElement.ts";
|
import { assertElement } from "../util/assertElement.ts";
|
||||||
|
|
||||||
let imgTimeoutID: number;
|
let imgTimeoutID: number;
|
||||||
|
const loadErrorSrc = `${settings.theme_static_path}/img/img_load_error.svg`;
|
||||||
|
|
||||||
const imageLoader = (resultElement: HTMLElement): void => {
|
const imageLoader = (resultElement: HTMLElement): void => {
|
||||||
if (imgTimeoutID) clearTimeout(imgTimeoutID);
|
if (imgTimeoutID) clearTimeout(imgTimeoutID);
|
||||||
@@ -15,7 +16,7 @@ const imageLoader = (resultElement: HTMLElement): void => {
|
|||||||
// use thumbnail until full image loads
|
// use thumbnail until full image loads
|
||||||
const thumbnail = resultElement.querySelector<HTMLImageElement>(".image_thumbnail");
|
const thumbnail = resultElement.querySelector<HTMLImageElement>(".image_thumbnail");
|
||||||
if (thumbnail) {
|
if (thumbnail) {
|
||||||
if (thumbnail.src === `${settings.theme_static_path}/img/img_load_error.svg`) return;
|
if (thumbnail.src === loadErrorSrc) return;
|
||||||
|
|
||||||
imgElement.onerror = (): void => {
|
imgElement.onerror = (): void => {
|
||||||
imgElement.src = thumbnail.src;
|
imgElement.src = thumbnail.src;
|
||||||
@@ -35,17 +36,27 @@ const imageLoader = (resultElement: HTMLElement): void => {
|
|||||||
}, 1000) as unknown as number;
|
}, 1000) as unknown as number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const imageThumbnails: NodeListOf<HTMLImageElement> = document.querySelectorAll<HTMLImageElement>(
|
const hideBrokenThumbnail = (img: HTMLImageElement): void => {
|
||||||
"#urls img.image_thumbnail, img.thumbnail"
|
if (img.classList.contains("thumbnail")) {
|
||||||
);
|
img.closest("a.thumbnail_link")?.remove();
|
||||||
for (const thumbnail of imageThumbnails) {
|
return;
|
||||||
if (thumbnail.complete && thumbnail.naturalWidth === 0) {
|
}
|
||||||
thumbnail.src = `${settings.theme_static_path}/img/img_load_error.svg`;
|
if (img.classList.contains("image_thumbnail") && img.src !== loadErrorSrc) {
|
||||||
|
img.src = loadErrorSrc;
|
||||||
}
|
}
|
||||||
|
|
||||||
thumbnail.onerror = (): void => {
|
|
||||||
thumbnail.src = `${settings.theme_static_path}/img/img_load_error.svg`;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
document.addEventListener(
|
||||||
|
"error",
|
||||||
|
(event: Event) => {
|
||||||
|
const img = event.target;
|
||||||
|
if (img instanceof HTMLImageElement) hideBrokenThumbnail(img);
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
// some images may have already failed
|
||||||
|
for (const img of document.querySelectorAll<HTMLImageElement>("img.thumbnail, #urls img.image_thumbnail")) {
|
||||||
|
if (img.complete && img.naturalWidth === 0) hideBrokenThumbnail(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
const copyUrlButton: HTMLButtonElement | null =
|
const copyUrlButton: HTMLButtonElement | null =
|
||||||
|
|||||||
@@ -255,6 +255,8 @@ article[data-vim-selected].category-social {
|
|||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: var(--color-result-url-font);
|
color: var(--color-result-url-font);
|
||||||
flex-flow: row nowrap;
|
flex-flow: row nowrap;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -305,22 +307,44 @@ article[data-vim-selected].category-social {
|
|||||||
|
|
||||||
a.thumbnail_link {
|
a.thumbnail_link {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-top: 0.6rem;
|
display: block;
|
||||||
.ltr-margin-right(1rem);
|
.ltr-float-right();
|
||||||
.ltr-float-left();
|
.ltr-margin-left(0.5rem);
|
||||||
|
width: 8rem;
|
||||||
|
aspect-ratio: 4 / 3;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
overflow: hidden;
|
||||||
|
background: var(--color-result-border);
|
||||||
|
|
||||||
|
img.thumbnail_bg {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
filter: blur(0.25rem);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
img.thumbnail {
|
img.thumbnail {
|
||||||
width: 7rem;
|
position: relative;
|
||||||
height: unset; // remove height value that was needed for lazy loading
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thumbnail_length {
|
.thumbnail_length {
|
||||||
.image-label-bottom-right();
|
.image-label-bottom-right();
|
||||||
right: 6px;
|
right: 6px;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.result_inner {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.break {
|
.break {
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
@@ -408,8 +432,12 @@ article[data-vim-selected].category-social {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.result-videos {
|
.result-videos {
|
||||||
a.thumbnail_link img.thumbnail {
|
a.thumbnail_link {
|
||||||
width: 20rem;
|
.ltr-float-left();
|
||||||
|
.ltr-margin-right(1rem);
|
||||||
|
.ltr-margin-left(0);
|
||||||
|
width: 10rem !important;
|
||||||
|
aspect-ratio: 16 / 9 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@@ -433,6 +461,8 @@ article[data-vim-selected].category-social {
|
|||||||
|
|
||||||
.engines {
|
.engines {
|
||||||
.ltr-float-right();
|
.ltr-float-right();
|
||||||
|
clear: both;
|
||||||
|
margin-top: 0.5rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
@@ -930,10 +960,6 @@ summary.title {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.result {
|
.result {
|
||||||
.thumbnail {
|
|
||||||
max-width: 98%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.url {
|
.url {
|
||||||
span.url {
|
span.url {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -1144,13 +1170,11 @@ summary.title {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@media screen and (max-width: @small-phone) {
|
@media screen and (max-width: @small-phone) {
|
||||||
.result-videos {
|
.result {
|
||||||
img.thumbnail {
|
a.thumbnail_link {
|
||||||
float: none !important;
|
aspect-ratio: 1 / 1;
|
||||||
}
|
width: 7rem;
|
||||||
|
border-radius: 1.25rem;
|
||||||
.content {
|
|
||||||
overflow: inherit;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,21 @@
|
|||||||
{{ result_open_link(url, classes) }}{{ title }}{{ result_close_link() }}
|
{{ result_open_link(url, classes) }}{{ title }}{{ result_close_link() }}
|
||||||
{%- endmacro -%}
|
{%- endmacro -%}
|
||||||
|
|
||||||
|
<!-- Draw result thumbnail -->
|
||||||
|
{% macro result_thumbnail(result, image_proxify) -%}
|
||||||
|
{%- if result.thumbnail -%}
|
||||||
|
{%- set thumb_src = image_proxify(result.thumbnail) -%}
|
||||||
|
{{ result_open_link(result.url, classes='thumbnail_link') -}}
|
||||||
|
<img class="thumbnail_bg" src="{{ thumb_src }}" alt="" aria-hidden="true"><img class="thumbnail" src="{{ thumb_src }}" alt="" loading="lazy">{%- if result.length -%}<span class="thumbnail_length">{{ result.length }}</span>{%- endif -%}
|
||||||
|
{{- result_close_link() -}}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endmacro -%}
|
||||||
|
|
||||||
<!-- Draw result header -->
|
<!-- Draw result header -->
|
||||||
{% macro result_header(result, favicons, image_proxify) -%}
|
{% macro result_header(result, favicons, image_proxify, thumbnail=True) -%}
|
||||||
<article class="result {% if result['template'] %}result-{{ result.template|replace('.html', '') }}{% else %}result-default{% endif %} {% if result['category'] %}category-{{ result['category'] }}{% endif %}">
|
<article class="result {% if result['template'] %}result-{{ result.template|replace('.html', '') }}{% else %}result-default{% endif %} {% if result['category'] %}category-{{ result['category'] }}{% endif %}">
|
||||||
|
{%- if thumbnail %}{{ result_thumbnail(result, image_proxify) }}{% endif -%}
|
||||||
|
<div class="result_inner">
|
||||||
{{- result_open_link(result.url, "url_header") -}}
|
{{- result_open_link(result.url, "url_header") -}}
|
||||||
{%- if favicon_resolver != "" %}
|
{%- if favicon_resolver != "" %}
|
||||||
<div class="favicon"><img loading="lazy" src="{{ favicon_url(result.parsed_url.netloc) }}"></div>
|
<div class="favicon"><img loading="lazy" src="{{ favicon_url(result.parsed_url.netloc) }}"></div>
|
||||||
@@ -30,7 +42,6 @@
|
|||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
</div>
|
</div>
|
||||||
{{- result_close_link() -}}
|
{{- result_close_link() -}}
|
||||||
{%- if result.thumbnail %}{{ result_open_link(result.url, classes='thumbnail_link') }}<img class="thumbnail" src="{{ image_proxify(result.thumbnail) }}" title="{{ result.title|striptags }}" loading="lazy">{%- if result.length -%}<span class="thumbnail_length">{{ result.length }}</span>{%- endif -%}{{ result_close_link() }}{% endif -%}
|
|
||||||
<h3>{{ result_link(result.url, result.title|safe) }}</h3>
|
<h3>{{ result_link(result.url, result.title|safe) }}</h3>
|
||||||
{%- endmacro -%}
|
{%- endmacro -%}
|
||||||
|
|
||||||
@@ -46,6 +57,7 @@
|
|||||||
|
|
||||||
<!-- Draw result sub footer -->
|
<!-- Draw result sub footer -->
|
||||||
{%- macro result_sub_footer(result) -%}
|
{%- macro result_sub_footer(result) -%}
|
||||||
|
</div>
|
||||||
<div class="engines">
|
<div class="engines">
|
||||||
{% for engine in result.engines %}<span>{{ engine }}</span>{% endfor %}
|
{% for engine in result.engines %}<span>{{ engine }}</span>{% endfor %}
|
||||||
{{ icon_small('ellipsis-vertical') + result_link(cache_url + result.url, _('cached'), "cache_link") }}
|
{{ icon_small('ellipsis-vertical') + result_link(cache_url + result.url, _('cached'), "cache_link") }}
|
||||||
|
|||||||
@@ -70,6 +70,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
</div>{{- '' -}}
|
</div>{{- '' -}}
|
||||||
|
</div>
|
||||||
<div class="break"></div>
|
<div class="break"></div>
|
||||||
|
|
||||||
{{- result_footer(result) }}
|
{{- result_footer(result) }}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
{% from 'simple/macros.html' import iframe, result_header, result_sub_header, result_sub_footer, result_footer with context %}
|
{% from 'simple/macros.html' import iframe, result_header, result_sub_header, result_sub_footer, result_footer, result_thumbnail with context %}
|
||||||
|
|
||||||
{{ result_header(result, favicons, image_proxify) }}
|
{{ result_header(result, favicons, image_proxify, thumbnail=False) }}
|
||||||
{{ result_sub_header(result) }}
|
{{ result_sub_header(result) }}
|
||||||
{% if result.iframe_src -%}
|
{% if result.iframe_src -%}
|
||||||
<p class="altlink"> <a class="btn-collapse collapsed media-loader disabled_if_nojs" data-target="#result-video-{{ index }}" data-btn-text-collapsed="{{ _('show video') }}" data-btn-text-not-collapsed="{{ _('hide video') }}">{{ icon_small('film') }} {{ _('show video') }}</a></p>
|
<p class="altlink"> <a class="btn-collapse collapsed media-loader disabled_if_nojs" data-target="#result-video-{{ index }}" data-btn-text-collapsed="{{ _('show video') }}" data-btn-text-not-collapsed="{{ _('hide video') }}">{{ icon_small('film') }} {{ _('show video') }}</a></p>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
{{ result_thumbnail(result, image_proxify) }}
|
||||||
{%- if result.content %}
|
{%- if result.content %}
|
||||||
<p class="content">
|
<p class="content">
|
||||||
{{ result.content|safe }}
|
{{ result.content|safe }}
|
||||||
@@ -14,7 +15,6 @@
|
|||||||
{{ _('This site did not provide any description.')|safe }}
|
{{ _('This site did not provide any description.')|safe }}
|
||||||
</p>
|
</p>
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
</p>
|
|
||||||
{{- result_sub_footer(result) -}}
|
{{- result_sub_footer(result) -}}
|
||||||
{% if result.iframe_src -%}
|
{% if result.iframe_src -%}
|
||||||
<div id="result-video-{{ index }}" class="embedded-video invisible">
|
<div id="result-video-{{ index }}" class="embedded-video invisible">
|
||||||
|
|||||||
Reference in New Issue
Block a user