Repository: searxng/searxng

Issue:
Image category: layout using flexbox instead of javascript
The image sizes are changed to fill the screen width:

Oscar:
![image](https://user-images.githubusercontent.com/1594191/135585174-3ba68eb4-5ef4-4659-94fb-3e7035895db9.png)

Simple theme:
![image](https://user-images.githubusercontent.com/1594191/135585247-2e4c8328-f6a0-4937-b295-cc23a77d37c1.png)


The current implementation use javascript: https://css-tricks.com/adaptive-photo-layout-with-flexbox/

It would be interesting to use CSS:
* to reduce the number of javascript files
* not to use the `style` attributes

Possible implementation: https://css-tricks.com/adaptive-photo-layout-with-flexbox/

The implementation can focus on the simple theme.




Discussion:
from https://github.com/searxng/searxng/issues/523#issuecomment-974117015
ping @mrpaulblack 

After a quick test, it works, but it requires to create HTML element to group the images when there are mixed result (from the general category and image category).

(I don't have a preference between flex or grid).
Just as a heads up I strongly prefer grid layout...
@mrpaulblack how would you rate it, is this PR a requirement for #665?
Yeah its part of the simple theme board, I am going to start working on the project in early January and tackle a lot of these issues... But please just hold on for a while, thanks :+1: 

[EDIT] and yeah I forgot this when I approved your PR earlier today :/

Resolving patch:
diff --git a/searx/results.py b/searx/results.py
--- a/searx/results.py
+++ b/searx/results.py
@@ -278,12 +278,18 @@ def _normalize_url_result(self, result):
             result['parsed_url'] = result['parsed_url']._replace(scheme="http")
             result['url'] = result['parsed_url'].geturl()
 
+        # avoid duplicate content between the content and title fields
+        if result.get('content') == result.get('title'):
+            del result['content']
+
+        # make sure there is a template
+        if 'template' not in result:
+            result['template'] = 'default.html'
+
         # strip multiple spaces and cariage returns from content
         if result.get('content'):
             result['content'] = WHITESPACE_REGEX.sub(' ', result['content'])
 
-        return True
-
     def __merge_url_result(self, result, position):
         result['engines'] = set([result['engine']])
         with self._lock:
diff --git a/searx/webapp.py b/searx/webapp.py
--- a/searx/webapp.py
+++ b/searx/webapp.py
@@ -726,6 +726,9 @@ def search():
     # Server-Timing header
     request.timings = result_container.get_timings()  # pylint: disable=assigning-non-slot
 
+    current_template = None
+    previous_result = None
+
     # output
     for result in results:
         if output_format == 'html':
@@ -762,6 +765,18 @@ def search():
                 else:
                     result['publishedDate'] = format_date(result['publishedDate'])
 
+        # set result['open_group'] = True when the template changes from the previous result
+        # set result['close_group'] = True when the template changes on the next result
+        if current_template != result.get('template'):
+            result['open_group'] = True
+            if previous_result:
+                previous_result['close_group'] = True  # pylint: disable=unsupported-assignment-operation
+        current_template = result.get('template')
+        previous_result = result
+
+    if previous_result:
+        previous_result['close_group'] = True
+
     if output_format == 'json':
         x = {
             'query': search_query.query,


Test patch:
diff --git a/tests/unit/test_webapp.py b/tests/unit/test_webapp.py
--- a/tests/unit/test_webapp.py
+++ b/tests/unit/test_webapp.py
@@ -33,7 +33,8 @@ def dummy(*args, **kwargs):
                 'engine': 'startpage',
                 'parsed_url': ParseResult(
                     scheme='http', netloc='first.test.xyz', path='/', params='', query='', fragment=''
-                ),  # noqa
+                ),
+                'template': 'default.html',
             },
             {
                 'content': 'second test content',
@@ -43,7 +44,8 @@ def dummy(*args, **kwargs):
                 'engine': 'youtube',
                 'parsed_url': ParseResult(
                     scheme='http', netloc='second.test.xyz', path='/', params='', query='', fragment=''
-                ),  # noqa
+                ),
+                'template': 'default.html',
             },
         ]