diff --git a/client/simple/src/js/main/results.ts b/client/simple/src/js/main/results.ts index 29cab399a..d3b22955c 100644 --- a/client/simple/src/js/main/results.ts +++ b/client/simple/src/js/main/results.ts @@ -5,6 +5,7 @@ import { listen, mutable, settings } from "../toolkit.ts"; import { assertElement } from "../util/assertElement.ts"; let imgTimeoutID: number; +const loadErrorSrc = `${settings.theme_static_path}/img/img_load_error.svg`; const imageLoader = (resultElement: HTMLElement): void => { if (imgTimeoutID) clearTimeout(imgTimeoutID); @@ -15,7 +16,7 @@ const imageLoader = (resultElement: HTMLElement): void => { // use thumbnail until full image loads const thumbnail = resultElement.querySelector(".image_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.src = thumbnail.src; @@ -35,17 +36,27 @@ const imageLoader = (resultElement: HTMLElement): void => { }, 1000) as unknown as number; }; -const imageThumbnails: NodeListOf = document.querySelectorAll( - "#urls img.image_thumbnail, img.thumbnail" -); -for (const thumbnail of imageThumbnails) { - if (thumbnail.complete && thumbnail.naturalWidth === 0) { - thumbnail.src = `${settings.theme_static_path}/img/img_load_error.svg`; +const hideBrokenThumbnail = (img: HTMLImageElement): void => { + if (img.classList.contains("thumbnail")) { + img.closest("a.thumbnail_link")?.remove(); + return; } + 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("img.thumbnail, #urls img.image_thumbnail")) { + if (img.complete && img.naturalWidth === 0) hideBrokenThumbnail(img); } const copyUrlButton: HTMLButtonElement | null = diff --git a/client/simple/src/less/style.less b/client/simple/src/less/style.less index 46ba5d491..3bb13e80f 100644 --- a/client/simple/src/less/style.less +++ b/client/simple/src/less/style.less @@ -255,6 +255,8 @@ article[data-vim-selected].category-social { font-size: 1rem; color: var(--color-result-url-font); flex-flow: row nowrap; + flex: 1; + min-width: 0; overflow: hidden; margin: 0; padding: 0; @@ -305,22 +307,44 @@ article[data-vim-selected].category-social { a.thumbnail_link { position: relative; - margin-top: 0.6rem; - .ltr-margin-right(1rem); - .ltr-float-left(); + display: block; + .ltr-float-right(); + .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 { - width: 7rem; - height: unset; // remove height value that was needed for lazy loading + position: relative; + width: 100%; + height: 100%; + object-fit: contain; display: block; } .thumbnail_length { .image-label-bottom-right(); right: 6px; + z-index: 1; } } + .result_inner { + overflow: hidden; + } + .break { clear: both; } @@ -408,8 +432,12 @@ article[data-vim-selected].category-social { } .result-videos { - a.thumbnail_link img.thumbnail { - width: 20rem; + a.thumbnail_link { + .ltr-float-left(); + .ltr-margin-right(1rem); + .ltr-margin-left(0); + width: 10rem !important; + aspect-ratio: 16 / 9 !important; } .content { @@ -433,6 +461,8 @@ article[data-vim-selected].category-social { .engines { .ltr-float-right(); + clear: both; + margin-top: 0.5rem; display: flex; flex-wrap: wrap; justify-content: flex-end; @@ -930,10 +960,6 @@ summary.title { } .result { - .thumbnail { - max-width: 98%; - } - .url { span.url { display: block; @@ -1144,13 +1170,11 @@ summary.title { */ @media screen and (max-width: @small-phone) { - .result-videos { - img.thumbnail { - float: none !important; - } - - .content { - overflow: inherit; + .result { + a.thumbnail_link { + aspect-ratio: 1 / 1; + width: 7rem; + border-radius: 1.25rem; } } } diff --git a/searx/templates/simple/macros.html b/searx/templates/simple/macros.html index 8941b6820..4e9ce324b 100644 --- a/searx/templates/simple/macros.html +++ b/searx/templates/simple/macros.html @@ -17,9 +17,21 @@ {{ result_open_link(url, classes) }}{{ title }}{{ result_close_link() }} {%- endmacro -%} + +{% macro result_thumbnail(result, image_proxify) -%} + {%- if result.thumbnail -%} + {%- set thumb_src = image_proxify(result.thumbnail) -%} + {{ result_open_link(result.url, classes='thumbnail_link') -}} + {%- if result.length -%}{{ result.length }}{%- endif -%} + {{- result_close_link() -}} + {%- endif -%} +{%- endmacro -%} + -{% macro result_header(result, favicons, image_proxify) -%} +{% macro result_header(result, favicons, image_proxify, thumbnail=True) -%}
+ {%- if thumbnail %}{{ result_thumbnail(result, image_proxify) }}{% endif -%} +
{{- result_open_link(result.url, "url_header") -}} {%- if favicon_resolver != "" %}
@@ -30,7 +42,6 @@ {%- endfor %}
{{- result_close_link() -}} - {%- if result.thumbnail %}{{ result_open_link(result.url, classes='thumbnail_link') }}{%- if result.length -%}{{ result.length }}{%- endif -%}{{ result_close_link() }}{% endif -%}

{{ result_link(result.url, result.title|safe) }}

{%- endmacro -%} @@ -46,6 +57,7 @@ {%- macro result_sub_footer(result) -%} +
{% for engine in result.engines %}{{ engine }}{% endfor %} {{ icon_small('ellipsis-vertical') + result_link(cache_url + result.url, _('cached'), "cache_link") }} diff --git a/searx/templates/simple/result_templates/packages.html b/searx/templates/simple/result_templates/packages.html index 8608621ba..12acbe39f 100644 --- a/searx/templates/simple/result_templates/packages.html +++ b/searx/templates/simple/result_templates/packages.html @@ -70,6 +70,7 @@
{%- endif -%} {{- '' -}} +
{{- result_footer(result) }} diff --git a/searx/templates/simple/result_templates/videos.html b/searx/templates/simple/result_templates/videos.html index a336c25ed..7e32306b1 100644 --- a/searx/templates/simple/result_templates/videos.html +++ b/searx/templates/simple/result_templates/videos.html @@ -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) }} {% if result.iframe_src -%} {%- endif %} +{{ result_thumbnail(result, image_proxify) }} {%- if result.content %}

{{ result.content|safe }} @@ -14,7 +15,6 @@ {{ _('This site did not provide any description.')|safe }}

{% endif -%} -

{{- result_sub_footer(result) -}} {% if result.iframe_src -%}