From a1132deaa4618f228e82252397247a150081a5f3 Mon Sep 17 00:00:00 2001 From: Markus Heiser Date: Thu, 23 Jan 2025 11:10:40 +0100 Subject: [web-client] simple theme: move sources to client/simple/src Signed-off-by: Markus Heiser --- client/simple/generated/pygments.less | 173 +++ client/simple/src/js/head/00_init.js | 20 + client/simple/src/js/main/00_toolkit.js | 165 +++ client/simple/src/js/main/infinite_scroll.js | 88 ++ client/simple/src/js/main/keyboard.js | 461 ++++++++ client/simple/src/js/main/mapresult.js | 74 ++ client/simple/src/js/main/preferences.js | 53 + client/simple/src/js/main/results.js | 181 +++ client/simple/src/js/main/search.js | 210 ++++ client/simple/src/less/animations.less | 19 + client/simple/src/less/autocomplete.less | 74 ++ client/simple/src/less/code.less | 51 + client/simple/src/less/definitions.less | 304 +++++ client/simple/src/less/detail.less | 253 +++++ client/simple/src/less/embedded.less | 33 + client/simple/src/less/index.less | 51 + client/simple/src/less/info.less | 10 + client/simple/src/less/mixins.less | 40 + client/simple/src/less/new_issue.less | 37 + client/simple/src/less/preferences.less | 233 ++++ client/simple/src/less/result_templates.less | 7 + client/simple/src/less/rss.less | 45 + client/simple/src/less/search.less | 393 +++++++ client/simple/src/less/stats.less | 106 ++ client/simple/src/less/style-center.less | 118 ++ client/simple/src/less/style-ltr.less | 85 ++ client/simple/src/less/style-rtl.less | 159 +++ client/simple/src/less/style.less | 1162 ++++++++++++++++++++ client/simple/src/less/toolkit.less | 646 +++++++++++ client/simple/src/less/toolkit_loader.less | 29 + .../simple/src/svg/information-circle-outline.svg | 6 + client/simple/src/svg/select-dark.svg | 4 + client/simple/src/svg/select-light.svg | 4 + .../themes/simple/src/generated/pygments.less | 173 --- searx/static/themes/simple/src/js/head/00_init.js | 20 - .../static/themes/simple/src/js/main/00_toolkit.js | 165 --- .../themes/simple/src/js/main/infinite_scroll.js | 88 -- searx/static/themes/simple/src/js/main/keyboard.js | 461 -------- .../static/themes/simple/src/js/main/mapresult.js | 74 -- .../themes/simple/src/js/main/preferences.js | 53 - searx/static/themes/simple/src/js/main/results.js | 181 --- searx/static/themes/simple/src/js/main/search.js | 207 ---- .../static/themes/simple/src/less/animations.less | 19 - .../themes/simple/src/less/autocomplete.less | 74 -- searx/static/themes/simple/src/less/code.less | 51 - .../static/themes/simple/src/less/definitions.less | 304 ----- searx/static/themes/simple/src/less/detail.less | 253 ----- searx/static/themes/simple/src/less/embedded.less | 33 - searx/static/themes/simple/src/less/index.less | 51 - searx/static/themes/simple/src/less/info.less | 10 - searx/static/themes/simple/src/less/mixins.less | 40 - searx/static/themes/simple/src/less/new_issue.less | 37 - .../static/themes/simple/src/less/preferences.less | 233 ---- .../themes/simple/src/less/result_templates.less | 7 - searx/static/themes/simple/src/less/rss.less | 45 - searx/static/themes/simple/src/less/search.less | 393 ------- searx/static/themes/simple/src/less/stats.less | 106 -- .../themes/simple/src/less/style-center.less | 118 -- searx/static/themes/simple/src/less/style-ltr.less | 85 -- searx/static/themes/simple/src/less/style-rtl.less | 159 --- searx/static/themes/simple/src/less/style.less | 1162 -------------------- searx/static/themes/simple/src/less/toolkit.less | 646 ----------- .../themes/simple/src/less/toolkit_loader.less | 29 - .../simple/src/svg/information-circle-outline.svg | 6 - searx/static/themes/simple/src/svg/select-dark.svg | 4 - .../static/themes/simple/src/svg/select-light.svg | 4 - 66 files changed, 5294 insertions(+), 5291 deletions(-) create mode 100644 client/simple/generated/pygments.less create mode 100644 client/simple/src/js/head/00_init.js create mode 100644 client/simple/src/js/main/00_toolkit.js create mode 100644 client/simple/src/js/main/infinite_scroll.js create mode 100644 client/simple/src/js/main/keyboard.js create mode 100644 client/simple/src/js/main/mapresult.js create mode 100644 client/simple/src/js/main/preferences.js create mode 100644 client/simple/src/js/main/results.js create mode 100644 client/simple/src/js/main/search.js create mode 100644 client/simple/src/less/animations.less create mode 100644 client/simple/src/less/autocomplete.less create mode 100644 client/simple/src/less/code.less create mode 100644 client/simple/src/less/definitions.less create mode 100644 client/simple/src/less/detail.less create mode 100644 client/simple/src/less/embedded.less create mode 100644 client/simple/src/less/index.less create mode 100644 client/simple/src/less/info.less create mode 100644 client/simple/src/less/mixins.less create mode 100644 client/simple/src/less/new_issue.less create mode 100644 client/simple/src/less/preferences.less create mode 100644 client/simple/src/less/result_templates.less create mode 100644 client/simple/src/less/rss.less create mode 100644 client/simple/src/less/search.less create mode 100644 client/simple/src/less/stats.less create mode 100644 client/simple/src/less/style-center.less create mode 100644 client/simple/src/less/style-ltr.less create mode 100644 client/simple/src/less/style-rtl.less create mode 100644 client/simple/src/less/style.less create mode 100644 client/simple/src/less/toolkit.less create mode 100644 client/simple/src/less/toolkit_loader.less create mode 100644 client/simple/src/svg/information-circle-outline.svg create mode 100644 client/simple/src/svg/select-dark.svg create mode 100644 client/simple/src/svg/select-light.svg delete mode 100644 searx/static/themes/simple/src/generated/pygments.less delete mode 100644 searx/static/themes/simple/src/js/head/00_init.js delete mode 100644 searx/static/themes/simple/src/js/main/00_toolkit.js delete mode 100644 searx/static/themes/simple/src/js/main/infinite_scroll.js delete mode 100644 searx/static/themes/simple/src/js/main/keyboard.js delete mode 100644 searx/static/themes/simple/src/js/main/mapresult.js delete mode 100644 searx/static/themes/simple/src/js/main/preferences.js delete mode 100644 searx/static/themes/simple/src/js/main/results.js delete mode 100644 searx/static/themes/simple/src/js/main/search.js delete mode 100644 searx/static/themes/simple/src/less/animations.less delete mode 100644 searx/static/themes/simple/src/less/autocomplete.less delete mode 100644 searx/static/themes/simple/src/less/code.less delete mode 100644 searx/static/themes/simple/src/less/definitions.less delete mode 100644 searx/static/themes/simple/src/less/detail.less delete mode 100644 searx/static/themes/simple/src/less/embedded.less delete mode 100644 searx/static/themes/simple/src/less/index.less delete mode 100644 searx/static/themes/simple/src/less/info.less delete mode 100644 searx/static/themes/simple/src/less/mixins.less delete mode 100644 searx/static/themes/simple/src/less/new_issue.less delete mode 100644 searx/static/themes/simple/src/less/preferences.less delete mode 100644 searx/static/themes/simple/src/less/result_templates.less delete mode 100644 searx/static/themes/simple/src/less/rss.less delete mode 100644 searx/static/themes/simple/src/less/search.less delete mode 100644 searx/static/themes/simple/src/less/stats.less delete mode 100644 searx/static/themes/simple/src/less/style-center.less delete mode 100644 searx/static/themes/simple/src/less/style-ltr.less delete mode 100644 searx/static/themes/simple/src/less/style-rtl.less delete mode 100644 searx/static/themes/simple/src/less/style.less delete mode 100644 searx/static/themes/simple/src/less/toolkit.less delete mode 100644 searx/static/themes/simple/src/less/toolkit_loader.less delete mode 100644 searx/static/themes/simple/src/svg/information-circle-outline.svg delete mode 100644 searx/static/themes/simple/src/svg/select-dark.svg delete mode 100644 searx/static/themes/simple/src/svg/select-light.svg diff --git a/client/simple/generated/pygments.less b/client/simple/generated/pygments.less new file mode 100644 index 000000000..971409116 --- /dev/null +++ b/client/simple/generated/pygments.less @@ -0,0 +1,173 @@ +/* + this file is generated automatically by searxng_extra/update/update_pygments.py + using pygments version 2.19.1 +*/ + + +.code-highlight { + + pre { line-height: 100%; } + td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } + span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } + td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } + span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } + .hll { background-color: #ffffcc } + .c { color: #3D7B7B; font-style: italic } /* Comment */ + .err { border: 1px solid #F00 } /* Error */ + .k { color: #008000; font-weight: bold } /* Keyword */ + .o { color: #666 } /* Operator */ + .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ + .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ + .cp { color: #9C6500 } /* Comment.Preproc */ + .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ + .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ + .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ + .gd { color: #A00000 } /* Generic.Deleted */ + .ge { font-style: italic } /* Generic.Emph */ + .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ + .gr { color: #E40000 } /* Generic.Error */ + .gh { color: #000080; font-weight: bold } /* Generic.Heading */ + .gi { color: #008400 } /* Generic.Inserted */ + .go { color: #717171 } /* Generic.Output */ + .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ + .gs { font-weight: bold } /* Generic.Strong */ + .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ + .gt { color: #04D } /* Generic.Traceback */ + .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ + .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ + .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ + .kp { color: #008000 } /* Keyword.Pseudo */ + .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ + .kt { color: #B00040 } /* Keyword.Type */ + .m { color: #666 } /* Literal.Number */ + .s { color: #BA2121 } /* Literal.String */ + .na { color: #687822 } /* Name.Attribute */ + .nb { color: #008000 } /* Name.Builtin */ + .nc { color: #00F; font-weight: bold } /* Name.Class */ + .no { color: #800 } /* Name.Constant */ + .nd { color: #A2F } /* Name.Decorator */ + .ni { color: #717171; font-weight: bold } /* Name.Entity */ + .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ + .nf { color: #00F } /* Name.Function */ + .nl { color: #767600 } /* Name.Label */ + .nn { color: #00F; font-weight: bold } /* Name.Namespace */ + .nt { color: #008000; font-weight: bold } /* Name.Tag */ + .nv { color: #19177C } /* Name.Variable */ + .ow { color: #A2F; font-weight: bold } /* Operator.Word */ + .w { color: #BBB } /* Text.Whitespace */ + .mb { color: #666 } /* Literal.Number.Bin */ + .mf { color: #666 } /* Literal.Number.Float */ + .mh { color: #666 } /* Literal.Number.Hex */ + .mi { color: #666 } /* Literal.Number.Integer */ + .mo { color: #666 } /* Literal.Number.Oct */ + .sa { color: #BA2121 } /* Literal.String.Affix */ + .sb { color: #BA2121 } /* Literal.String.Backtick */ + .sc { color: #BA2121 } /* Literal.String.Char */ + .dl { color: #BA2121 } /* Literal.String.Delimiter */ + .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ + .s2 { color: #BA2121 } /* Literal.String.Double */ + .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ + .sh { color: #BA2121 } /* Literal.String.Heredoc */ + .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ + .sx { color: #008000 } /* Literal.String.Other */ + .sr { color: #A45A77 } /* Literal.String.Regex */ + .s1 { color: #BA2121 } /* Literal.String.Single */ + .ss { color: #19177C } /* Literal.String.Symbol */ + .bp { color: #008000 } /* Name.Builtin.Pseudo */ + .fm { color: #00F } /* Name.Function.Magic */ + .vc { color: #19177C } /* Name.Variable.Class */ + .vg { color: #19177C } /* Name.Variable.Global */ + .vi { color: #19177C } /* Name.Variable.Instance */ + .vm { color: #19177C } /* Name.Variable.Magic */ + .il { color: #666 } /* Literal.Number.Integer.Long */ +} + +.code-highlight-dark(){ + .code-highlight { + + pre { line-height: 100%; } + td.linenos .normal { color: #3c4354; background-color: transparent; padding-left: 5px; padding-right: 5px; } + span.linenos { color: #3c4354; background-color: transparent; padding-left: 5px; padding-right: 5px; } + td.linenos .special { color: #3c4354; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } + span.linenos.special { color: #3c4354; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } + .hll { background-color: #6e7681 } + .c { color: #7E8AA1 } /* Comment */ + .err { color: #F88F7F } /* Error */ + .esc { color: #D4D2C8 } /* Escape */ + .g { color: #D4D2C8 } /* Generic */ + .k { color: #FFAD66 } /* Keyword */ + .l { color: #D5FF80 } /* Literal */ + .n { color: #D4D2C8 } /* Name */ + .o { color: #FFAD66 } /* Operator */ + .x { color: #D4D2C8 } /* Other */ + .p { color: #D4D2C8 } /* Punctuation */ + .ch { color: #F88F7F; font-style: italic } /* Comment.Hashbang */ + .cm { color: #7E8AA1 } /* Comment.Multiline */ + .cp { color: #FFAD66; font-weight: bold } /* Comment.Preproc */ + .cpf { color: #7E8AA1 } /* Comment.PreprocFile */ + .c1 { color: #7E8AA1 } /* Comment.Single */ + .cs { color: #7E8AA1; font-style: italic } /* Comment.Special */ + .gd { color: #F88F7F; background-color: #3D1E20 } /* Generic.Deleted */ + .ge { color: #D4D2C8; font-style: italic } /* Generic.Emph */ + .ges { color: #D4D2C8 } /* Generic.EmphStrong */ + .gr { color: #F88F7F } /* Generic.Error */ + .gh { color: #D4D2C8 } /* Generic.Heading */ + .gi { color: #6AD4AF; background-color: #19362C } /* Generic.Inserted */ + .go { color: #7E8AA1 } /* Generic.Output */ + .gp { color: #D4D2C8 } /* Generic.Prompt */ + .gs { color: #D4D2C8; font-weight: bold } /* Generic.Strong */ + .gu { color: #D4D2C8 } /* Generic.Subheading */ + .gt { color: #F88F7F } /* Generic.Traceback */ + .kc { color: #FFAD66 } /* Keyword.Constant */ + .kd { color: #FFAD66 } /* Keyword.Declaration */ + .kn { color: #FFAD66 } /* Keyword.Namespace */ + .kp { color: #FFAD66 } /* Keyword.Pseudo */ + .kr { color: #FFAD66 } /* Keyword.Reserved */ + .kt { color: #73D0FF } /* Keyword.Type */ + .ld { color: #D5FF80 } /* Literal.Date */ + .m { color: #DFBFFF } /* Literal.Number */ + .s { color: #D5FF80 } /* Literal.String */ + .na { color: #FFD173 } /* Name.Attribute */ + .nb { color: #FFD173 } /* Name.Builtin */ + .nc { color: #73D0FF } /* Name.Class */ + .no { color: #FFD173 } /* Name.Constant */ + .nd { color: #7E8AA1; font-weight: bold; font-style: italic } /* Name.Decorator */ + .ni { color: #95E6CB } /* Name.Entity */ + .ne { color: #73D0FF } /* Name.Exception */ + .nf { color: #FFD173 } /* Name.Function */ + .nl { color: #D4D2C8 } /* Name.Label */ + .nn { color: #D4D2C8 } /* Name.Namespace */ + .nx { color: #D4D2C8 } /* Name.Other */ + .py { color: #FFD173 } /* Name.Property */ + .nt { color: #5CCFE6 } /* Name.Tag */ + .nv { color: #D4D2C8 } /* Name.Variable */ + .ow { color: #FFAD66 } /* Operator.Word */ + .pm { color: #D4D2C8 } /* Punctuation.Marker */ + .w { color: #D4D2C8 } /* Text.Whitespace */ + .mb { color: #DFBFFF } /* Literal.Number.Bin */ + .mf { color: #DFBFFF } /* Literal.Number.Float */ + .mh { color: #DFBFFF } /* Literal.Number.Hex */ + .mi { color: #DFBFFF } /* Literal.Number.Integer */ + .mo { color: #DFBFFF } /* Literal.Number.Oct */ + .sa { color: #F29E74 } /* Literal.String.Affix */ + .sb { color: #D5FF80 } /* Literal.String.Backtick */ + .sc { color: #D5FF80 } /* Literal.String.Char */ + .dl { color: #D5FF80 } /* Literal.String.Delimiter */ + .sd { color: #7E8AA1 } /* Literal.String.Doc */ + .s2 { color: #D5FF80 } /* Literal.String.Double */ + .se { color: #95E6CB } /* Literal.String.Escape */ + .sh { color: #D5FF80 } /* Literal.String.Heredoc */ + .si { color: #95E6CB } /* Literal.String.Interpol */ + .sx { color: #95E6CB } /* Literal.String.Other */ + .sr { color: #95E6CB } /* Literal.String.Regex */ + .s1 { color: #D5FF80 } /* Literal.String.Single */ + .ss { color: #DFBFFF } /* Literal.String.Symbol */ + .bp { color: #5CCFE6 } /* Name.Builtin.Pseudo */ + .fm { color: #FFD173 } /* Name.Function.Magic */ + .vc { color: #D4D2C8 } /* Name.Variable.Class */ + .vg { color: #D4D2C8 } /* Name.Variable.Global */ + .vi { color: #D4D2C8 } /* Name.Variable.Instance */ + .vm { color: #D4D2C8 } /* Name.Variable.Magic */ + .il { color: #DFBFFF } /* Literal.Number.Integer.Long */ + } +} diff --git a/client/simple/src/js/head/00_init.js b/client/simple/src/js/head/00_init.js new file mode 100644 index 000000000..a7c61c43e --- /dev/null +++ b/client/simple/src/js/head/00_init.js @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later */ +(function (w, d) { + 'use strict'; + + // add data- properties + var script = d.currentScript || (function () { + var scripts = d.getElementsByTagName('script'); + return scripts[scripts.length - 1]; + })(); + + w.searxng = { + settings: JSON.parse(atob(script.getAttribute('client_settings'))) + }; + + // update the css + var htmlElement = d.getElementsByTagName("html")[0]; + htmlElement.classList.remove('no-js'); + htmlElement.classList.add('js'); + +})(window, document); diff --git a/client/simple/src/js/main/00_toolkit.js b/client/simple/src/js/main/00_toolkit.js new file mode 100644 index 000000000..4e374a019 --- /dev/null +++ b/client/simple/src/js/main/00_toolkit.js @@ -0,0 +1,165 @@ +/** + * @license + * (C) Copyright Contributors to the SearXNG project. + * (C) Copyright Contributors to the searx project (2014 - 2021). + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +window.searxng = (function (w, d) { + + 'use strict'; + + // not invented here toolkit with bugs fixed elsewhere + // purposes : be just good enough and as small as possible + + // from https://plainjs.com/javascript/events/live-binding-event-handlers-14/ + if (w.Element) { + (function (ElementPrototype) { + ElementPrototype.matches = ElementPrototype.matches || + ElementPrototype.matchesSelector || + ElementPrototype.webkitMatchesSelector || + ElementPrototype.msMatchesSelector || + function (selector) { + var node = this, nodes = (node.parentNode || node.document).querySelectorAll(selector), i = -1; + while (nodes[++i] && nodes[i] != node); + return !!nodes[i]; + }; + })(Element.prototype); + } + + function callbackSafe (callback, el, e) { + try { + callback.call(el, e); + } catch (exception) { + console.log(exception); + } + } + + var searxng = window.searxng || {}; + + searxng.on = function (obj, eventType, callback, useCapture) { + useCapture = useCapture || false; + if (typeof obj !== 'string') { + // obj HTMLElement, HTMLDocument + obj.addEventListener(eventType, callback, useCapture); + } else { + // obj is a selector + d.addEventListener(eventType, function (e) { + var el = e.target || e.srcElement, found = false; + while (el && el.matches && el !== d && !(found = el.matches(obj))) el = el.parentElement; + if (found) callbackSafe(callback, el, e); + }, useCapture); + } + }; + + searxng.ready = function (callback) { + if (document.readyState != 'loading') { + callback.call(w); + } else { + w.addEventListener('DOMContentLoaded', callback.bind(w)); + } + }; + + searxng.http = function (method, url, data = null) { + return new Promise(function (resolve, reject) { + try { + var req = new XMLHttpRequest(); + req.open(method, url, true); + req.timeout = 20000; + + // On load + req.onload = function () { + if (req.status == 200) { + resolve(req.response, req.responseType); + } else { + reject(Error(req.statusText)); + } + }; + + // Handle network errors + req.onerror = function () { + reject(Error("Network Error")); + }; + + req.onabort = function () { + reject(Error("Transaction is aborted")); + }; + + req.ontimeout = function () { + reject(Error("Timeout")); + } + + // Make the request + if (data) { + req.send(data) + } else { + req.send(); + } + } catch (ex) { + reject(ex); + } + }); + }; + + searxng.loadStyle = function (src) { + var path = searxng.settings.theme_static_path + "/" + src, + id = "style_" + src.replace('.', '_'), + s = d.getElementById(id); + if (s === null) { + s = d.createElement('link'); + s.setAttribute('id', id); + s.setAttribute('rel', 'stylesheet'); + s.setAttribute('type', 'text/css'); + s.setAttribute('href', path); + d.body.appendChild(s); + } + }; + + searxng.loadScript = function (src, callback) { + var path = searxng.settings.theme_static_path + "/" + src, + id = "script_" + src.replace('.', '_'), + s = d.getElementById(id); + if (s === null) { + s = d.createElement('script'); + s.setAttribute('id', id); + s.setAttribute('src', path); + s.onload = callback; + s.onerror = function () { + s.setAttribute('error', '1'); + }; + d.body.appendChild(s); + } else if (!s.hasAttribute('error')) { + try { + callback.apply(s, []); + } catch (exception) { + console.log(exception); + } + } else { + console.log("callback not executed : script '" + path + "' not loaded."); + } + }; + + searxng.insertBefore = function (newNode, referenceNode) { + referenceNode.parentNode.insertBefore(newNode, referenceNode); + }; + + searxng.insertAfter = function (newNode, referenceNode) { + referenceNode.parentNode.insertAfter(newNode, referenceNode.nextSibling); + }; + + searxng.on('.close', 'click', function () { + this.parentNode.classList.add('invisible'); + }); + + function getEndpoint () { + for (var className of d.getElementsByTagName('body')[0].classList.values()) { + if (className.endsWith('_endpoint')) { + return className.split('_')[0]; + } + } + return ''; + } + + searxng.endpoint = getEndpoint(); + + return searxng; +})(window, document); diff --git a/client/simple/src/js/main/infinite_scroll.js b/client/simple/src/js/main/infinite_scroll.js new file mode 100644 index 000000000..07db3305a --- /dev/null +++ b/client/simple/src/js/main/infinite_scroll.js @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +/* global searxng */ + +searxng.ready(function () { + 'use strict'; + + searxng.infinite_scroll_supported = ( + 'IntersectionObserver' in window && + 'IntersectionObserverEntry' in window && + 'intersectionRatio' in window.IntersectionObserverEntry.prototype); + + if (searxng.endpoint !== 'results') { + return; + } + + if (!searxng.infinite_scroll_supported) { + console.log('IntersectionObserver not supported'); + return; + } + + let d = document; + var onlyImages = d.getElementById('results').classList.contains('only_template_images'); + + function newLoadSpinner () { + var loader = d.createElement('div'); + loader.classList.add('loader'); + return loader; + } + + function replaceChildrenWith (element, children) { + element.textContent = ''; + children.forEach(child => element.appendChild(child)); + } + + function loadNextPage (callback) { + var form = d.querySelector('#pagination form.next_page'); + if (!form) { + return + } + replaceChildrenWith(d.querySelector('#pagination'), [ newLoadSpinner() ]); + var formData = new FormData(form); + searxng.http('POST', d.querySelector('#search').getAttribute('action'), formData).then( + function (response) { + var nextPageDoc = new DOMParser().parseFromString(response, 'text/html'); + var articleList = nextPageDoc.querySelectorAll('#urls article'); + var paginationElement = nextPageDoc.querySelector('#pagination'); + d.querySelector('#pagination').remove(); + if (articleList.length > 0 && !onlyImages) { + // do not add
element when there are only images + d.querySelector('#urls').appendChild(d.createElement('hr')); + } + articleList.forEach(articleElement => { + d.querySelector('#urls').appendChild(articleElement); + }); + if (paginationElement) { + d.querySelector('#results').appendChild(paginationElement); + callback(); + } + } + ).catch( + function (err) { + console.log(err); + var e = d.createElement('div'); + e.textContent = searxng.settings.translations.error_loading_next_page; + e.classList.add('dialog-error'); + e.setAttribute('role', 'alert'); + replaceChildrenWith(d.querySelector('#pagination'), [ e ]); + } + ) + } + + if (searxng.settings.infinite_scroll && searxng.infinite_scroll_supported) { + const intersectionObserveOptions = { + rootMargin: "20rem", + }; + const observedSelector = 'article.result:last-child'; + const observer = new IntersectionObserver(entries => { + const paginationEntry = entries[0]; + if (paginationEntry.isIntersecting) { + observer.unobserve(paginationEntry.target); + loadNextPage(() => observer.observe(d.querySelector(observedSelector), intersectionObserveOptions)); + } + }); + observer.observe(d.querySelector(observedSelector), intersectionObserveOptions); + } + +}); diff --git a/client/simple/src/js/main/keyboard.js b/client/simple/src/js/main/keyboard.js new file mode 100644 index 000000000..e16134579 --- /dev/null +++ b/client/simple/src/js/main/keyboard.js @@ -0,0 +1,461 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later */ +/* global searxng */ + +searxng.ready(function () { + + function isElementInDetail (el) { + while (el !== undefined) { + if (el.classList.contains('detail')) { + return true; + } + if (el.classList.contains('result')) { + // we found a result, no need to go to the root of the document: + // el is not inside a
element + return false; + } + el = el.parentNode; + } + return false; + } + + function getResultElement (el) { + while (el !== undefined) { + if (el.classList.contains('result')) { + return el; + } + el = el.parentNode; + } + return undefined; + } + + function isImageResult (resultElement) { + return resultElement && resultElement.classList.contains('result-images'); + } + + searxng.on('.result', 'click', function (e) { + if (!isElementInDetail(e.target)) { + highlightResult(this)(true, true); + let resultElement = getResultElement(e.target); + if (isImageResult(resultElement)) { + e.preventDefault(); + searxng.selectImage(resultElement); + } + } + }); + + searxng.on('.result a', 'focus', function (e) { + if (!isElementInDetail(e.target)) { + let resultElement = getResultElement(e.target); + if (resultElement && resultElement.getAttribute("data-vim-selected") === null) { + highlightResult(resultElement)(true); + } + if (isImageResult(resultElement)) { + searxng.selectImage(resultElement); + } + } + }, true); + + /* common base for layouts */ + var baseKeyBinding = { + 'Escape': { + key: 'ESC', + fun: removeFocus, + des: 'remove focus from the focused input', + cat: 'Control' + }, + 'c': { + key: 'c', + fun: copyURLToClipboard, + des: 'copy url of the selected result to the clipboard', + cat: 'Results' + }, + 'h': { + key: 'h', + fun: toggleHelp, + des: 'toggle help window', + cat: 'Other' + }, + 'i': { + key: 'i', + fun: searchInputFocus, + des: 'focus on the search input', + cat: 'Control' + }, + 'n': { + key: 'n', + fun: GoToNextPage(), + des: 'go to next page', + cat: 'Results' + }, + 'o': { + key: 'o', + fun: openResult(false), + des: 'open search result', + cat: 'Results' + }, + 'p': { + key: 'p', + fun: GoToPreviousPage(), + des: 'go to previous page', + cat: 'Results' + }, + 'r': { + key: 'r', + fun: reloadPage, + des: 'reload page from the server', + cat: 'Control' + }, + 't': { + key: 't', + fun: openResult(true), + des: 'open the result in a new tab', + cat: 'Results' + }, + }; + var keyBindingLayouts = { + + "default": Object.assign( + { /* SearXNG layout */ + 'ArrowLeft': { + key: '←', + fun: highlightResult('up'), + des: 'select previous search result', + cat: 'Results' + }, + 'ArrowRight': { + key: '→', + fun: highlightResult('down'), + des: 'select next search result', + cat: 'Results' + }, + }, baseKeyBinding), + + 'vim': Object.assign( + { /* Vim-like Key Layout. */ + 'b': { + key: 'b', + fun: scrollPage(-window.innerHeight), + des: 'scroll one page up', + cat: 'Navigation' + }, + 'f': { + key: 'f', + fun: scrollPage(window.innerHeight), + des: 'scroll one page down', + cat: 'Navigation' + }, + 'u': { + key: 'u', + fun: scrollPage(-window.innerHeight / 2), + des: 'scroll half a page up', + cat: 'Navigation' + }, + 'd': { + key: 'd', + fun: scrollPage(window.innerHeight / 2), + des: 'scroll half a page down', + cat: 'Navigation' + }, + 'g': { + key: 'g', + fun: scrollPageTo(-document.body.scrollHeight, 'top'), + des: 'scroll to the top of the page', + cat: 'Navigation' + }, + 'v': { + key: 'v', + fun: scrollPageTo(document.body.scrollHeight, 'bottom'), + des: 'scroll to the bottom of the page', + cat: 'Navigation' + }, + 'k': { + key: 'k', + fun: highlightResult('up'), + des: 'select previous search result', + cat: 'Results' + }, + 'j': { + key: 'j', + fun: highlightResult('down'), + des: 'select next search result', + cat: 'Results' + }, + 'y': { + key: 'y', + fun: copyURLToClipboard, + des: 'copy url of the selected result to the clipboard', + cat: 'Results' + }, + }, baseKeyBinding) + } + + var keyBindings = keyBindingLayouts[searxng.settings.hotkeys] || keyBindingLayouts.default; + + searxng.on(document, "keydown", function (e) { + // check for modifiers so we don't break browser's hotkeys + if ( + Object.prototype.hasOwnProperty.call(keyBindings, e.key) + && !e.ctrlKey && !e.altKey + && !e.shiftKey && !e.metaKey + ) { + var tagName = e.target.tagName.toLowerCase(); + if (e.key === 'Escape') { + keyBindings[e.key].fun(e); + } else { + if (e.target === document.body || tagName === 'a' || tagName === 'button') { + e.preventDefault(); + keyBindings[e.key].fun(); + } + } + } + }); + + function highlightResult (which) { + return function (noScroll, keepFocus) { + var current = document.querySelector('.result[data-vim-selected]'), + effectiveWhich = which; + if (current === null) { + // no selection : choose the first one + current = document.querySelector('.result'); + if (current === null) { + // no first one : there are no results + return; + } + // replace up/down actions by selecting first one + if (which === "down" || which === "up") { + effectiveWhich = current; + } + } + + var next, results = document.querySelectorAll('.result'); + results = Array.from(results); // convert NodeList to Array for further use + + if (typeof effectiveWhich !== 'string') { + next = effectiveWhich; + } else { + switch (effectiveWhich) { + case 'visible': + var top = document.documentElement.scrollTop || document.body.scrollTop; + var bot = top + document.documentElement.clientHeight; + + for (var i = 0; i < results.length; i++) { + next = results[i]; + var etop = next.offsetTop; + var ebot = etop + next.clientHeight; + + if ((ebot <= bot) && (etop > top)) { + break; + } + } + break; + case 'down': + next = results[results.indexOf(current) + 1] || current; + break; + case 'up': + next = results[results.indexOf(current) - 1] || current; + break; + case 'bottom': + next = results[results.length - 1]; + break; + case 'top': + /* falls through */ + default: + next = results[0]; + } + } + + if (next) { + current.removeAttribute('data-vim-selected'); + next.setAttribute('data-vim-selected', 'true'); + if (!keepFocus) { + var link = next.querySelector('h3 a') || next.querySelector('a'); + if (link !== null) { + link.focus(); + } + } + if (!noScroll) { + scrollPageToSelected(); + } + } + }; + } + + function reloadPage () { + document.location.reload(true); + } + + function removeFocus (e) { + const tagName = e.target.tagName.toLowerCase(); + if (document.activeElement && (tagName === 'input' || tagName === 'select' || tagName === 'textarea')) { + document.activeElement.blur(); + } else { + searxng.closeDetail(); + } + } + + function pageButtonClick (css_selector) { + return function () { + var button = document.querySelector(css_selector); + if (button) { + button.click(); + } + }; + } + + function GoToNextPage () { + return pageButtonClick('nav#pagination .next_page button[type="submit"]'); + } + + function GoToPreviousPage () { + return pageButtonClick('nav#pagination .previous_page button[type="submit"]'); + } + + function scrollPageToSelected () { + var sel = document.querySelector('.result[data-vim-selected]'); + if (sel === null) { + return; + } + var wtop = document.documentElement.scrollTop || document.body.scrollTop, + wheight = document.documentElement.clientHeight, + etop = sel.offsetTop, + ebot = etop + sel.clientHeight, + offset = 120; + // first element ? + if ((sel.previousElementSibling === null) && (ebot < wheight)) { + // set to the top of page if the first element + // is fully included in the viewport + window.scroll(window.scrollX, 0); + return; + } + if (wtop > (etop - offset)) { + window.scroll(window.scrollX, etop - offset); + } else { + var wbot = wtop + wheight; + if (wbot < (ebot + offset)) { + window.scroll(window.scrollX, ebot - wheight + offset); + } + } + } + + function scrollPage (amount) { + return function () { + window.scrollBy(0, amount); + highlightResult('visible')(); + }; + } + + function scrollPageTo (position, nav) { + return function () { + window.scrollTo(0, position); + highlightResult(nav)(); + }; + } + + function searchInputFocus () { + window.scrollTo(0, 0); + var q = document.querySelector('#q'); + q.focus(); + if (q.setSelectionRange) { + var len = q.value.length; + q.setSelectionRange(len, len); + } + } + + function openResult (newTab) { + return function () { + var link = document.querySelector('.result[data-vim-selected] h3 a'); + if (link === null) { + link = document.querySelector('.result[data-vim-selected] > a'); + } + if (link !== null) { + var url = link.getAttribute('href'); + if (newTab) { + window.open(url); + } else { + window.location.href = url; + } + } + }; + } + + function initHelpContent (divElement) { + var categories = {}; + + for (var k in keyBindings) { + var key = keyBindings[k]; + categories[key.cat] = categories[key.cat] || []; + categories[key.cat].push(key); + } + + var sorted = Object.keys(categories).sort(function (a, b) { + return categories[b].length - categories[a].length; + }); + + if (sorted.length === 0) { + return; + } + + var html = '×'; + html += '

How to navigate SearXNG with hotkeys

'; + html += ''; + + for (var i = 0; i < sorted.length; i++) { + var cat = categories[sorted[i]]; + + var lastCategory = i === (sorted.length - 1); + var first = i % 2 === 0; + + if (first) { + html += ''; + } + html += ''; // col-sm-* + + if (!first || lastCategory) { + html += ''; // row + } + } + + html += '
'; + + html += '

' + cat[0].cat + '

'; + html += '
    '; + + for (var cj in cat) { + html += '
  • ' + cat[cj].key + ' ' + cat[cj].des + '
  • '; + } + + html += '
'; + html += '
'; + + divElement.innerHTML = html; + } + + function toggleHelp () { + var helpPanel = document.querySelector('#vim-hotkeys-help'); + if (helpPanel === undefined || helpPanel === null) { + // first call + helpPanel = document.createElement('div'); + helpPanel.id = 'vim-hotkeys-help'; + helpPanel.className = 'dialog-modal'; + initHelpContent(helpPanel); + var body = document.getElementsByTagName('body')[0]; + body.appendChild(helpPanel); + } else { + // toggle hidden + helpPanel.classList.toggle('invisible'); + return; + } + } + + function copyURLToClipboard () { + var currentUrlElement = document.querySelector('.result[data-vim-selected] h3 a'); + if (currentUrlElement === null) return; + + const url = currentUrlElement.getAttribute('href'); + navigator.clipboard.writeText(url); + } + + searxng.scrollPageToSelected = scrollPageToSelected; + searxng.selectNext = highlightResult('down'); + searxng.selectPrevious = highlightResult('up'); +}); diff --git a/client/simple/src/js/main/mapresult.js b/client/simple/src/js/main/mapresult.js new file mode 100644 index 000000000..2c3777678 --- /dev/null +++ b/client/simple/src/js/main/mapresult.js @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later */ +/* global L */ +(function (w, d, searxng) { + 'use strict'; + + searxng.ready(function () { + searxng.on('.searxng_init_map', 'click', function (event) { + // no more request + this.classList.remove("searxng_init_map"); + + // + var leaflet_target = this.dataset.leafletTarget; + var map_lon = parseFloat(this.dataset.mapLon); + var map_lat = parseFloat(this.dataset.mapLat); + var map_zoom = parseFloat(this.dataset.mapZoom); + var map_boundingbox = JSON.parse(this.dataset.mapBoundingbox); + var map_geojson = JSON.parse(this.dataset.mapGeojson); + + searxng.loadStyle('css/leaflet.css'); + searxng.loadScript('js/leaflet.js', function () { + var map_bounds = null; + if (map_boundingbox) { + var southWest = L.latLng(map_boundingbox[0], map_boundingbox[2]); + var northEast = L.latLng(map_boundingbox[1], map_boundingbox[3]); + map_bounds = L.latLngBounds(southWest, northEast); + } + + // init map + var map = L.map(leaflet_target); + // create the tile layer with correct attribution + var osmMapnikUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; + var osmMapnikAttrib = 'Map data © OpenStreetMap contributors'; + var osmMapnik = new L.TileLayer(osmMapnikUrl, {minZoom: 1, maxZoom: 19, attribution: osmMapnikAttrib}); + var osmWikimediaUrl = 'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png'; + var osmWikimediaAttrib = 'Wikimedia maps | Maps data © OpenStreetMap contributors'; + var osmWikimedia = new L.TileLayer(osmWikimediaUrl, {minZoom: 1, maxZoom: 19, attribution: osmWikimediaAttrib}); + // init map view + if (map_bounds) { + // TODO hack: https://github.com/Leaflet/Leaflet/issues/2021 + // Still useful ? + setTimeout(function () { + map.fitBounds(map_bounds, { + maxZoom: 17 + }); + }, 0); + } else if (map_lon && map_lat) { + if (map_zoom) { + map.setView(new L.latLng(map_lat, map_lon), map_zoom); + } else { + map.setView(new L.latLng(map_lat, map_lon), 8); + } + } + + map.addLayer(osmMapnik); + + var baseLayers = { + "OSM Mapnik": osmMapnik, + "OSM Wikimedia": osmWikimedia, + }; + + L.control.layers(baseLayers).addTo(map); + + if (map_geojson) { + L.geoJson(map_geojson).addTo(map); + } /* else if(map_bounds) { + L.rectangle(map_bounds, {color: "#ff7800", weight: 3, fill:false}).addTo(map); + } */ + }); + + // this event occur only once per element + event.preventDefault(); + }); + }); +})(window, document, window.searxng); diff --git a/client/simple/src/js/main/preferences.js b/client/simple/src/js/main/preferences.js new file mode 100644 index 000000000..a0b853d61 --- /dev/null +++ b/client/simple/src/js/main/preferences.js @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later */ +(function (w, d, searxng) { + 'use strict'; + + if (searxng.endpoint !== 'preferences') { + return; + } + + searxng.ready(function () { + let engine_descriptions = null; + function load_engine_descriptions () { + if (engine_descriptions == null) { + searxng.http("GET", "engine_descriptions.json").then(function (content) { + engine_descriptions = JSON.parse(content); + for (const [engine_name, description] of Object.entries(engine_descriptions)) { + let elements = d.querySelectorAll('[data-engine-name="' + engine_name + '"] .engine-description'); + for (const element of elements) { + let source = ' (' + searxng.settings.translations.Source + ': ' + description[1] + ')'; + element.innerHTML = description[0] + source; + } + } + }); + } + } + + for (const el of d.querySelectorAll('[data-engine-name]')) { + searxng.on(el, 'mouseenter', load_engine_descriptions); + } + + const enableAllEngines = d.querySelectorAll(".enable-all-engines"); + const disableAllEngines = d.querySelectorAll(".disable-all-engines"); + const engineToggles = d.querySelectorAll('tbody input[type=checkbox][class~=checkbox-onoff]'); + const toggleEngines = (enable) => { + for (const el of engineToggles) { + // check if element visible, so that only engines of the current category are modified + if (el.offsetParent !== null) el.checked = !enable; + } + }; + for (const el of enableAllEngines) { + searxng.on(el, 'click', () => toggleEngines(true)); + } + for (const el of disableAllEngines) { + searxng.on(el, 'click', () => toggleEngines(false)); + } + + const copyHashButton = d.querySelector("#copy-hash"); + searxng.on(copyHashButton, 'click', (e) => { + e.preventDefault(); + navigator.clipboard.writeText(copyHashButton.dataset.hash); + copyHashButton.innerText = copyHashButton.dataset.copiedText; + }); + }); +})(window, document, window.searxng); diff --git a/client/simple/src/js/main/results.js b/client/simple/src/js/main/results.js new file mode 100644 index 000000000..cc7c7efcd --- /dev/null +++ b/client/simple/src/js/main/results.js @@ -0,0 +1,181 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later */ +(function (w, d, searxng) { + 'use strict'; + + if (searxng.endpoint !== 'results') { + return; + } + + searxng.ready(function () { + d.querySelectorAll('#urls img').forEach( + img => + img.addEventListener( + 'error', () => { + // console.log("ERROR can't load: " + img.src); + img.src = window.searxng.settings.theme_static_path + "/img/img_load_error.svg"; + }, + {once: true} + )); + + if (d.querySelector('#search_url button#copy_url')) { + d.querySelector('#search_url button#copy_url').style.display = "block"; + } + + searxng.on('.btn-collapse', 'click', function () { + var btnLabelCollapsed = this.getAttribute('data-btn-text-collapsed'); + var btnLabelNotCollapsed = this.getAttribute('data-btn-text-not-collapsed'); + var target = this.getAttribute('data-target'); + var targetElement = d.querySelector(target); + var html = this.innerHTML; + if (this.classList.contains('collapsed')) { + html = html.replace(btnLabelCollapsed, btnLabelNotCollapsed); + } else { + html = html.replace(btnLabelNotCollapsed, btnLabelCollapsed); + } + this.innerHTML = html; + this.classList.toggle('collapsed'); + targetElement.classList.toggle('invisible'); + }); + + searxng.on('.media-loader', 'click', function () { + var target = this.getAttribute('data-target'); + var iframe_load = d.querySelector(target + ' > iframe'); + var srctest = iframe_load.getAttribute('src'); + if (srctest === null || srctest === undefined || srctest === false) { + iframe_load.setAttribute('src', iframe_load.getAttribute('data-src')); + } + }); + + searxng.on('#copy_url', 'click', function () { + var target = this.parentElement.querySelector('pre'); + navigator.clipboard.writeText(target.innerText); + this.innerText = this.dataset.copiedText; + }); + + // searxng.selectImage (gallery) + // ----------------------------- + + // setTimeout() ID, needed to cancel *last* loadImage + let imgTimeoutID; + + // progress spinner, while an image is loading + const imgLoaderSpinner = d.createElement('div'); + imgLoaderSpinner.classList.add('loader'); + + // singleton image object, which is used for all loading processes of a + // detailed image + const imgLoader = new Image(); + + const loadImage = (imgSrc, onSuccess) => { + // if defered image load exists, stop defered task. + if (imgTimeoutID) clearTimeout(imgTimeoutID); + + // defer load of the detail image for 1 sec + imgTimeoutID = setTimeout(() => { + imgLoader.src = imgSrc; + }, 1000); + + // set handlers in the on-properties + imgLoader.onload = () => { + onSuccess(); + imgLoaderSpinner.remove(); + }; + imgLoader.onerror = () => { + imgLoaderSpinner.remove(); + }; + }; + + searxng.selectImage = (resultElement) => { + + // add a class that can be evaluated in the CSS and indicates that the + // detail view is open + d.getElementById('results').classList.add('image-detail-open'); + + // add a hash to the browser history so that pressing back doesn't return + // to the previous page this allows us to dismiss the image details on + // pressing the back button on mobile devices + window.location.hash = '#image-viewer'; + + searxng.scrollPageToSelected(); + + // if there is none element given by the caller, stop here + if (!resultElement) return; + + // find object in the element, if there is none, stop here. + const img = resultElement.querySelector('.result-images-source img'); + if (!img) return; + + // + const src = img.getAttribute('data-src'); + + // already loaded high-res image or no high-res image available + if (!src) return; + + // use the image thumbnail until the image is fully loaded + const thumbnail = resultElement.querySelector('.image_thumbnail'); + img.src = thumbnail.src; + + // show a progress spinner + const detailElement = resultElement.querySelector('.detail'); + detailElement.appendChild(imgLoaderSpinner); + + // load full size image in background + loadImage(src, () => { + // after the singelton loadImage has loaded the detail image into the + // cache, it can be used in the origin as src property. + img.src = src; + img.removeAttribute('data-src'); + }); + }; + + searxng.closeDetail = function () { + d.getElementById('results').classList.remove('image-detail-open'); + // remove #image-viewer hash from url by navigating back + if (window.location.hash == '#image-viewer') window.history.back(); + searxng.scrollPageToSelected(); + }; + searxng.on('.result-detail-close', 'click', e => { + e.preventDefault(); + searxng.closeDetail(); + }); + searxng.on('.result-detail-previous', 'click', e => { + e.preventDefault(); + searxng.selectPrevious(false); + }); + searxng.on('.result-detail-next', 'click', e => { + e.preventDefault(); + searxng.selectNext(false); + }); + + // listen for the back button to be pressed and dismiss the image details when called + window.addEventListener('hashchange', () => { + if (window.location.hash != '#image-viewer') searxng.closeDetail(); + }); + + d.querySelectorAll('.swipe-horizontal').forEach( + obj => { + obj.addEventListener('swiped-left', function () { + searxng.selectNext(false); + }); + obj.addEventListener('swiped-right', function () { + searxng.selectPrevious(false); + }); + } + ); + + w.addEventListener('scroll', function () { + var e = d.getElementById('backToTop'), + scrollTop = document.documentElement.scrollTop || document.body.scrollTop, + results = d.getElementById('results'); + if (e !== null) { + if (scrollTop >= 100) { + results.classList.add('scrolling'); + } else { + results.classList.remove('scrolling'); + } + } + }, true); + + }); + +})(window, document, window.searxng); diff --git a/client/simple/src/js/main/search.js b/client/simple/src/js/main/search.js new file mode 100644 index 000000000..aca146c41 --- /dev/null +++ b/client/simple/src/js/main/search.js @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later */ +/* exported AutoComplete */ + +import AutoComplete from "../../../node_modules/autocomplete-js/dist/autocomplete.js"; + +(function (w, d, searxng) { + 'use strict'; + + var qinput_id = "q", qinput; + + const isMobile = window.matchMedia("only screen and (max-width: 50em)").matches; + + function submitIfQuery () { + if (qinput.value.length > 0) { + var search = document.getElementById('search'); + setTimeout(search.submit.bind(search), 0); + } + } + + function createClearButton (qinput) { + var cs = document.getElementById('clear_search'); + var updateClearButton = function () { + if (qinput.value.length === 0) { + cs.classList.add("empty"); + } else { + cs.classList.remove("empty"); + } + }; + + // update status, event listener + updateClearButton(); + cs.addEventListener('click', function (ev) { + qinput.value = ''; + qinput.focus(); + updateClearButton(); + ev.preventDefault(); + }); + qinput.addEventListener('input', updateClearButton, false); + } + + searxng.ready(function () { + qinput = d.getElementById(qinput_id); + + if (qinput !== null) { + // clear button + createClearButton(qinput); + + // autocompleter + if (searxng.settings.autocomplete) { + searxng.autocomplete = AutoComplete.call(w, { + Url: "./autocompleter", + EmptyMessage: searxng.settings.translations.no_item_found, + HttpMethod: searxng.settings.method, + HttpHeaders: { + "Content-type": "application/x-www-form-urlencoded", + "X-Requested-With": "XMLHttpRequest" + }, + MinChars: searxng.settings.autocomplete_min, + Delay: 300, + _Position: function () {}, + _Open: function () { + var params = this; + Array.prototype.forEach.call(this.DOMResults.getElementsByTagName("li"), function (li) { + if (li.getAttribute("class") != "locked") { + li.onmousedown = function () { + params._Select(li); + }; + } + }); + }, + _Select: function (item) { + AutoComplete.defaults._Select.call(this, item); + var form = item.closest('form'); + if (form) { + form.submit(); + } + }, + _MinChars: function () { + if (this.Input.value.indexOf('!') > -1) { + return 0; + } else { + return AutoComplete.defaults._MinChars.call(this); + } + }, + KeyboardMappings: Object.assign({}, AutoComplete.defaults.KeyboardMappings, { + "KeyUpAndDown_up": Object.assign({}, AutoComplete.defaults.KeyboardMappings.KeyUpAndDown_up, { + Callback: function (event) { + AutoComplete.defaults.KeyboardMappings.KeyUpAndDown_up.Callback.call(this, event); + var liActive = this.DOMResults.querySelector("li.active"); + if (liActive) { + AutoComplete.defaults._Select.call(this, liActive); + } + }, + }), + "Tab": Object.assign({}, AutoComplete.defaults.KeyboardMappings.Enter, { + Conditions: [{ + Is: 9, + Not: false + }], + Callback: function (event) { + if (this.DOMResults.getAttribute("class").indexOf("open") != -1) { + var liActive = this.DOMResults.querySelector("li.active"); + if (liActive !== null) { + AutoComplete.defaults._Select.call(this, liActive); + event.preventDefault(); + } + } + }, + }) + }), + }, "#" + qinput_id); + } + + /* + Monkey patch autocomplete.js to fix a bug + With the POST method, the values are not URL encoded: query like "1 + 1" are sent as "1 1" since space are URL encoded as plus. + See HTML specifications: + * HTML5: https://url.spec.whatwg.org/#concept-urlencoded-serializer + * HTML4: https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1 + + autocomplete.js does not URL encode the name and values: + https://github.com/autocompletejs/autocomplete.js/blob/87069524f3b95e68f1b54d8976868e0eac1b2c83/src/autocomplete.ts#L665 + + The monkey patch overrides the compiled version of the ajax function. + See https://github.com/autocompletejs/autocomplete.js/blob/87069524f3b95e68f1b54d8976868e0eac1b2c83/dist/autocomplete.js#L143-L158 + The patch changes only the line 156 from + params.Request.send(params._QueryArg() + "=" + params._Pre()); + to + params.Request.send(encodeURIComponent(params._QueryArg()) + "=" + encodeURIComponent(params._Pre())); + + Related to: + * https://github.com/autocompletejs/autocomplete.js/issues/78 + * https://github.com/searxng/searxng/issues/1695 + */ + AutoComplete.prototype.ajax = function (params, request, timeout) { + if (timeout === void 0) { timeout = true; } + if (params.$AjaxTimer) { + window.clearTimeout(params.$AjaxTimer); + } + if (timeout === true) { + params.$AjaxTimer = window.setTimeout(AutoComplete.prototype.ajax.bind(null, params, request, false), params.Delay); + } else { + if (params.Request) { + params.Request.abort(); + } + params.Request = request; + params.Request.send(encodeURIComponent(params._QueryArg()) + "=" + encodeURIComponent(params._Pre())); + } + }; + + if (!isMobile && document.querySelector('.index_endpoint')) { + qinput.focus(); + } + } + + // Additionally to searching when selecting a new category, we also + // automatically start a new search request when the user changes a search + // filter (safesearch, time range or language) (this requires JavaScript + // though) + if ( + qinput !== null + && searxng.settings.search_on_category_select + // If .search_filters is undefined (invisible) we are on the homepage and + // hence don't have to set any listeners + && d.querySelector(".search_filters") != null + ) { + searxng.on(d.getElementById('safesearch'), 'change', submitIfQuery); + searxng.on(d.getElementById('time_range'), 'change', submitIfQuery); + searxng.on(d.getElementById('language'), 'change', submitIfQuery); + } + + const categoryButtons = d.querySelectorAll("button.category_button"); + for (let button of categoryButtons) { + searxng.on(button, 'click', (event) => { + if (event.shiftKey) { + event.preventDefault(); + button.classList.toggle("selected"); + return; + } + + // manually deselect the old selection when a new category is selected + const selectedCategories = d.querySelectorAll("button.category_button.selected"); + for (let categoryButton of selectedCategories) { + categoryButton.classList.remove("selected"); + } + button.classList.add("selected"); + }) + } + + // override form submit action to update the actually selected categories + const form = d.querySelector("#search"); + if (form != null) { + searxng.on(form, 'submit', (event) => { + event.preventDefault(); + const categoryValuesInput = d.querySelector("#selected-categories"); + if (categoryValuesInput) { + let categoryValues = []; + for (let categoryButton of categoryButtons) { + if (categoryButton.classList.contains("selected")) { + categoryValues.push(categoryButton.name.replace("category_", "")); + } + } + categoryValuesInput.value = categoryValues.join(","); + } + form.submit(); + }); + } + }); + +})(window, document, window.searxng); diff --git a/client/simple/src/less/animations.less b/client/simple/src/less/animations.less new file mode 100644 index 000000000..75c98308f --- /dev/null +++ b/client/simple/src/less/animations.less @@ -0,0 +1,19 @@ +.dialog-modal { + animation-name: dialogmodal; + animation-duration: 0.13s; + + @keyframes dialogmodal { + 0% { + opacity: 0; + } + + 50% { + opacity: 0.5; + transform: translate(-50%, -50%) scale(1.05); + } + } +} + +input.checkbox-onoff[type="checkbox"]::before { + transition: left 0.25s; +} diff --git a/client/simple/src/less/autocomplete.less b/client/simple/src/less/autocomplete.less new file mode 100644 index 000000000..8285ff2c6 --- /dev/null +++ b/client/simple/src/less/autocomplete.less @@ -0,0 +1,74 @@ +/*! Autocomplete.js v2.6.3 | license MIT | (c) 2017, Baptiste Donaux | http://autocomplete-js.com */ + +.autocomplete { + position: absolute; + width: @search-width; + max-height: 0; + overflow-y: hidden; + .ltr-text-align-left(); + + .rounded-corners; + + &:active, + &:focus, + &:hover { + background-color: var(--color-autocomplete-background); + } + + &:empty { + display: none; + } + + > ul { + list-style-type: none; + margin: 0; + padding: 0; + + > li { + cursor: pointer; + padding: 0.5rem 1rem; + + &.active, + &:active, + &:focus, + &:hover { + background-color: var(--color-autocomplete-background-hover); + + a:active, + a:focus, + a:hover { + text-decoration: none; + } + } + + &.locked { + cursor: inherit; + } + } + } + + &.open { + display: block; + background-color: var(--color-autocomplete-background); + color: var(--color-autocomplete-font); + max-height: 32rem; + overflow-y: auto; + z-index: 5000; + margin-top: 3.5rem; + border-radius: 0.8rem; + + &:empty { + display: none; + } + } +} + +@media screen and (max-width: @phone) { + .autocomplete { + width: 100%; + + > ul > li { + padding: 1rem; + } + } +} diff --git a/client/simple/src/less/code.less b/client/simple/src/less/code.less new file mode 100644 index 000000000..dd0998b23 --- /dev/null +++ b/client/simple/src/less/code.less @@ -0,0 +1,51 @@ +@import "../../generated/pygments.less"; + +.codelines { + margin: @results-margin 0 0 0; + padding: @result-padding 0 0 0; +} + +.code-highlight-sxng() { + .code-highlight { + pre { + overflow: auto; + margin: 0; + padding: 0 0 0.75rem 0; + } + + .linenos { + user-select: none; + cursor: default; + + &::selection { + background: transparent; /* WebKit/Blink Browsers */ + } + + &::-moz-selection { + background: transparent; /* Gecko Browsers */ + } + margin-right: 8px; + text-align: right; + } + + span.linenos { + color: var(--color-line-number); + } + } +} + +.code-highlight-sxng(); + +/// Dark Theme (autoswitch based on device pref) +@media (prefers-color-scheme: dark) { + :root.theme-auto { + .code-highlight-dark(); + .code-highlight-sxng(); + } +} + +// Dark Theme by preferences +:root.theme-dark { + .code-highlight-dark(); + .code-highlight-sxng(); +} diff --git a/client/simple/src/less/definitions.less b/client/simple/src/less/definitions.less new file mode 100644 index 000000000..7501305fc --- /dev/null +++ b/client/simple/src/less/definitions.less @@ -0,0 +1,304 @@ +/* + * SearXNG, A privacy-respecting, hackable metasearch engine + * + * To change the colors of the site, simple edit this variables + */ + +/// Light Theme +:root { + /// Base Colors + --color-base-font: #444; + --color-base-font-rgb: 68, 68, 68; + --color-base-background: #fff; + --color-base-background-mobile: #f2f5f8; + --color-url-font: #334999; + --color-url-visited-font: #9822c3; + /// Header Colors + --color-header-background: #fdfbff; + --color-header-border: #ddd; + /// Footer Colors + --color-footer-background: #fdfbff; + --color-footer-border: #ddd; + /// Sidebar Colors + --color-sidebar-border: #ddd; + --color-sidebar-font: #000; + --color-sidebar-background: #fff; + /// BackToTop Colors + --color-backtotop-font: #444; + --color-backtotop-border: #ddd; + --color-backtotop-background: #fff; + /// Button Colors + --color-btn-background: #3050ff; + --color-btn-font: #fff; + --color-show-btn-background: #bbb; + --color-show-btn-font: #000; + /// Search Input Colors + --color-search-border: #bbb; + --color-search-shadow: 0 2px 8px rgb(34 38 46 / 25%); + --color-search-background: #fff; + --color-search-font: #222; + --color-search-background-hover: #3050ff; + /// Modal Colors + --color-error: #db3434; + --color-error-background: lighten(#db3434, 40%); + --color-warning: #dbba34; + --color-warning-background: lighten(#dbba34, 40%); + --color-success: #42db34; + --color-success-background: lighten(#42db34, 40%); + /// Categories Colors + --color-categories-item-selected-font: #3050ff; + --color-categories-item-border-selected: #3050ff; + /// Autocomplete Colors + --color-autocomplete-font: #000; + --color-autocomplete-border: #bbb; + --color-autocomplete-shadow: 0 2px 8px rgb(34 38 46 / 25%); + --color-autocomplete-background: #fff; + --color-autocomplete-background-hover: #e3e3e3; + /// Answer Colors + --color-answer-font: #444; // same as --color-base-font + --color-answer-background: #fff; + /// Results Colors + --color-result-background: #fff; + --color-result-border: #ddd; + --color-result-url-font: #000; + --color-result-vim-selected: #f7f7f7; + --color-result-vim-arrow: #000bbb; + --color-result-description-highlight-font: #000; + --color-result-link-font: #000bbb; + --color-result-link-font-highlight: #000bbb; + --color-result-link-visited-font: #9822c3; + --color-result-publishdate-font: #777; + --color-result-engines-font: #545454; + --color-result-search-url-border: #ddd; + --color-result-search-url-font: #000; + // Images Colors + --color-result-image-span-font: #444; + --color-result-image-span-font-selected: #fff; + --color-result-image-background: #fff; + /// Settings Colors + --color-settings-tr-hover: #ebebeb; + --color-settings-engine-description-font: #545454; + --color-settings-table-group-background: #0001; + /// Detail modal + --color-result-detail-font: #fff; + --color-result-detail-label-font: lightgray; + --color-result-detail-background: #242424; + --color-result-detail-hr: #555; + --color-result-detail-link: #8af; + --color-result-detail-loader-border: rgb(255 255 255 / 20%); + --color-result-detail-loader-borderleft: rgb(0 0 0 / 0%); + /// Toolkit Colors + --color-toolkit-badge-font: #fff; + --color-toolkit-badge-background: #545454; + --color-toolkit-kbd-font: #fff; + --color-toolkit-kbd-background: #000; + --color-toolkit-dialog-border: #ddd; + --color-toolkit-dialog-background: #fff; + --color-toolkit-tabs-label-border: #fff; + --color-toolkit-tabs-section-border: #ddd; + --color-toolkit-select-background: #e1e1e1; + --color-toolkit-select-border: #ddd; + --color-toolkit-select-background-hover: #bbb; + --color-toolkit-input-text-font: #222; + --color-toolkit-checkbox-onoff-off-background: #ddd; + --color-toolkit-checkbox-onoff-on-background: #ddd; + --color-toolkit-checkbox-onoff-on-mark-background: #3050ff; + --color-toolkit-checkbox-onoff-on-mark-color: #fff; + --color-toolkit-checkbox-onoff-off-mark-background: #aaa; + --color-toolkit-checkbox-onoff-off-mark-color: #fff; + --color-toolkit-checkbox-label-background: #ddd; + --color-toolkit-checkbox-label-border: #ddd; + --color-toolkit-checkbox-input-border: #3050ff; + --color-toolkit-engine-tooltip-border: #ddd; + --color-toolkit-engine-tooltip-background: #fff; + --color-toolkit-loader-border: rgb(0 0 0 / 20%); + --color-toolkit-loader-borderleft: rgb(255 255 255 / 0%); + --color-doc-code: #003; + --color-doc-code-background: #ddeaff; + /// Other misc colors + --color-bar-chart-primary: #5bc0de; + --color-bar-chart-secondary: #deb15b; + --color-image-resolution-background: rgb(0 0 0 / 50%); + --color-image-resolution-font: #fff; + --color-loading-indicator: rgb(255 255 255 / 20%); + --color-loading-indicator-gap: #fff; + --color-line-number: #64708d; + // Favicons Colors + --color-favicon-background-color: #ddd; + --color-favicon-border-color: #ccc; +} + +.dark-themes() { + /// Base Colors + --color-base-font: #bbb; + --color-base-font-rgb: 187, 187, 187; + --color-base-background: #222428; + --color-base-background-mobile: #222428; + --color-url-font: #8af; + --color-url-visited-font: #c09cd9; + /// Header Colors + --color-header-background: #1e1e22; + --color-header-border: #333; + /// Footer Colors + --color-footer-background: #1e1e22; + --color-footer-border: #333; + /// Sidebar Colors + --color-sidebar-border: #555; + --color-sidebar-font: #fff; + --color-sidebar-background: #292c34; + /// BackToTop Colors + --color-backtotop-font: #bbb; + --color-backtotop-border: #333; + --color-backtotop-background: #2b2e36; + /// Button Colors + --color-btn-background: #58f; + --color-btn-font: #222; + --color-show-btn-background: #555; + --color-show-btn-font: #fff; + /// Search Input Colors + --color-search-border: #555; + --color-search-shadow: 0 2px 8px rgb(34 38 46 / 25%); + --color-search-background: #2b2e36; + --color-search-font: #fff; + --color-search-background-hover: #58f; + /// Modal Colors + --color-error: #f55b5b; + --color-error-background: darken(#db3434, 40%); + --color-warning: #f1d561; + --color-warning-background: darken(#dbba34, 40%); + --color-success: #79f56e; + --color-success-background: darken(#42db34, 40%); + /// Categories Colors + --color-categories-item-selected-font: #58f; + --color-categories-item-border-selected: #58f; + /// Autocomplete Colors + --color-autocomplete-font: #fff; + --color-autocomplete-border: #555; + --color-autocomplete-shadow: 0 2px 8px rgb(34 38 46 / 25%); + --color-autocomplete-background: #2b2e36; + --color-autocomplete-background-hover: #1e1e22; + /// Answer Colors + --color-answer-font: #bbb; // same as --color-base-font + --color-answer-background: #26292f; + /// Results Colors + --color-result-background: #26292f; + --color-result-border: #333; + --color-result-url-font: #fff; + --color-result-vim-selected: #1f1f23cc; + --color-result-vim-arrow: #8af; + --color-result-description-highlight-font: #fff; + --color-result-link-font: #8af; + --color-result-link-font-highlight: #8af; + --color-result-link-visited-font: #c09cd9; + --color-result-publishdate-font: #888; + --color-result-engines-font: #a4a4a4; + --color-result-search-url-border: #555; + --color-result-search-url-font: #fff; + /// Detail modal : same as the light version + --color-result-detail-font: #fff; + --color-result-detail-label-font: lightgray; + --color-result-detail-background: #1a1a1c; + --color-result-detail-hr: #555; + --color-result-detail-link: #8af; + --color-result-detail-loader-border: rgb(255 255 255 / 20%); + --color-result-detail-loader-borderleft: rgb(0 0 0 / 0%); + // Images Colors + --color-result-image-span-font: #bbb; + --color-result-image-span-font-selected: #222; + --color-result-image-background: #222; + /// Settings Colors + --color-settings-tr-hover: #2c2c32; + --color-settings-engine-description-font: darken(#dcdcdc, 30%); + --color-settings-table-group-background: #1b1b21; + /// Toolkit Colors + --color-toolkit-badge-font: #fff; + --color-toolkit-badge-background: #555; + --color-toolkit-kbd-font: #000; + --color-toolkit-kbd-background: #fff; + --color-toolkit-dialog-border: #555; + --color-toolkit-dialog-background: #1e1e22; + --color-toolkit-tabs-label-border: #222; + --color-toolkit-tabs-section-border: #555; + --color-toolkit-select-background: #313338; + --color-toolkit-select-border: #555; + --color-toolkit-select-background-hover: #373b49; + --color-toolkit-input-text-font: #fff; + --color-toolkit-checkbox-onoff-off-background: #313338; + --color-toolkit-checkbox-onoff-on-background: #313338; + --color-toolkit-checkbox-onoff-on-mark-background: #58f; + --color-toolkit-checkbox-onoff-on-mark-color: #222; + --color-toolkit-checkbox-onoff-off-mark-background: #ddd; + --color-toolkit-checkbox-onoff-off-mark-color: #222; + --color-toolkit-checkbox-label-background: #222; + --color-toolkit-checkbox-label-border: #333; + --color-toolkit-checkbox-input-border: #58f; + --color-toolkit-engine-tooltip-border: #333; + --color-toolkit-engine-tooltip-background: #222; + --color-toolkit-loader-border: rgb(255 255 255 / 20%); + --color-toolkit-loader-borderleft: rgb(0 0 0 / 0%); + --color-doc-code: #ddd; + --color-doc-code-background: #4d5a6f; + // Favicons Colors + --color-favicon-background-color: #ddd; + --color-favicon-border-color: #ccc; +} + +.black-themes() { + --color-base-background: #000; + --color-base-background-mobile: #000; + --color-header-background: #000; + --color-footer-background: #000; + --color-sidebar-background: #000; +} + +/// Dark Theme (autoswitch based on device pref) +@media (prefers-color-scheme: dark) { + :root.theme-auto { + .dark-themes(); + } +} + +// Dark Theme by preferences +:root.theme-dark { + .dark-themes(); +} + +:root.theme-black { + .dark-themes(); + .black-themes(); +} + +/// General Size +@results-width: 45rem; +@results-sidebar-width: 25rem; +@results-offset: 10rem; +@results-tablet-offset: 0.5rem; +@results-gap: 5rem; +@results-margin: 0.125rem; +@result-padding: 1rem; +@results-image-row-height: 12rem; +@results-image-row-height-phone: 10rem; +@search-width: 44rem; +// heigh of #search, see detail.less +@search-height: 13rem; + +/// Device Size +/// @desktop > @tablet +@tablet: 79.75em; // see https://github.com/searxng/searxng/issues/874 +@phone: 50em; +@small-phone: 35em; +@ultra-small-phone: 20rem; + +/// From style.less +@stacked-bar-chart: rgb(0, 0, 0); + +/// Load fonts from this directory. +@icon-font-path: "../../../fonts/"; +//** File name for all font files. +@icon-font-name: "glyphicons-halflings-regular"; +//** Element ID within SVG icon file. +@icon-font-svg-id: "glyphicons_halflingsregular"; + +// decoration of the select HTML elements +@select-light-svg-path: "../svg/select-light.svg"; +@select-dark-svg-path: "../svg/select-dark.svg"; diff --git a/client/simple/src/less/detail.less b/client/simple/src/less/detail.less new file mode 100644 index 000000000..fd5cd8e05 --- /dev/null +++ b/client/simple/src/less/detail.less @@ -0,0 +1,253 @@ +#main_results #results.image-detail-open.only_template_images { + width: min(98%, 59.25rem) !important; +} + +#main_results #results.only_template_images.image-detail-open #backToTop { + .ltr-left(56.75rem) !important; + .ltr-right(inherit); +} + +article.result-images .detail { + display: none; +} + +#results.image-detail-open article.result-images[data-vim-selected] .detail { + display: flex; + flex-direction: column; + position: fixed; + .ltr-left(60rem); + .ltr-right(0); + top: @search-height; + transition: top 0.064s ease-in 0s; + bottom: 0; + background: var(--color-result-detail-background); + border: 1px solid var(--color-result-detail-background); + z-index: 1000; + padding: 4rem 3rem 3rem 3rem; + + a.result-images-source { + display: block; + flex: 1; + text-align: left; + width: 100%; + border: none; + text-decoration: none; + + img { + padding: 0; + margin: 0; + border: none; + object-fit: contain; + width: inherit; + height: inherit; + max-width: 100%; + min-height: inherit; + max-height: calc(100vh - 25rem - 7rem); + background: inherit; + } + } + + .result-images-labels { + color: var(--color-result-detail-font); + height: 19rem; + + hr { + border-top: 1px solid var(--color-result-detail-hr); + border-bottom: none; + } + + h4 { + height: 2rem; + overflow: hidden; + text-overflow: ellipsis; + font-size: 0.9rem; + margin-bottom: 0; + } + + p { + color: var(--color-result-detail-label-font); + font-size: 0.9rem; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + margin: 0.8rem 0; + + span { + display: inline-block; + width: 12rem; + } + } + + h4, + p, + a { + .ltr-text-align-left(); + } + + p.result-content { + height: 2rem; + line-height: unset; + overflow: hidden; + text-overflow: ellipsis; + } + + p.result-url { + white-space: nowrap; + overflow: hidden hidden; + text-overflow: ellipsis; + } + + p.result-content:hover, + p.result-url:hover { + position: relative; + overflow: inherit !important; + background: var(--color-result-detail-background); + text-overflow: inherit !important; + } + + a, + a:visited, + a:hover, + a:active { + color: var(--color-result-detail-link); + } + + a:hover { + text-decoration: underline; + } + } + + a.result-detail-close { + top: 1rem; + .ltr-left(1rem); + padding: 0.4rem; + } + + a.result-detail-previous { + top: 1rem; + .ltr-right(6rem); + // center the icon by moving it slightly on the left + padding-top: 0.4rem; + .ltr-padding-right(0.5rem); + padding-bottom: 0.4rem; + .ltr-padding-left(0.3rem); + } + + a.result-detail-next { + top: 1rem; + .ltr-right(2rem); + padding: 0.4rem; + } + + a.result-detail-close, + a.result-detail-next, + a.result-detail-previous { + border-radius: 50%; + display: block; + width: 1.5rem; + height: 1.5rem; + position: absolute; + filter: opacity(40%); + z-index: 1200; + + span { + display: block; + width: 1.5rem; + height: 1.5rem; + text-align: center; + } + } + + a.result-detail-next, + a.result-detail-previous { + span::before { + // vertical center small icons + vertical-align: sub; + } + } + + a.result-detail-close, + a.result-detail-close:visited, + a.result-detail-close:hover, + a.result-detail-close:active, + a.result-detail-previous, + a.result-detail-previous:visited, + a.result-detail-previous:hover, + a.result-detail-previous:active, + a.result-detail-next, + a.result-detail-next:visited, + a.result-detail-next:hover, + a.result-detail-next:active { + color: var(--color-result-detail-font); + background: var(--color-result-detail-background); + border: 1px solid var(--color-result-detail-font); + } + + a.result-detail-close:focus, + a.result-detail-close:hover, + a.result-detail-previous:focus, + a.result-detail-previous:hover, + a.result-detail-next:focus, + a.result-detail-next:hover { + filter: opacity(80%); + } + + .loader { + position: absolute; + top: 1rem; + .ltr-right(50%); + border-top: 0.5em solid var(--color-result-detail-loader-border); + border-right: 0.5em solid var(--color-result-detail-loader-border); + border-bottom: 0.5em solid var(--color-result-detail-loader-border); + border-left: 0.5em solid var(--color-result-detail-loader-borderleft); + } +} + +#results.image-detail-open.scrolling article.result-images[data-vim-selected] .detail { + top: 0; + + a.result-images-source img { + max-height: calc(100vh - 25rem); + } +} + +@media screen and (max-width: @tablet) { + #results.image-detail-open article.result-images[data-vim-selected] .detail { + top: 0; + .ltr-left(0); + + a.result-images-source { + display: flex; + flex-direction: column; + justify-content: center; + + img { + width: 100%; + max-height: calc(100vh - 24rem); + } + } + + a.result-detail-next { + .ltr-right(1rem); + } + } +} + +@media screen and (max-width: @phone) { + #results.image-detail-open article.result-images[data-vim-selected] .detail { + top: 0; + .ltr-left(0); + padding: 1rem; + + a.result-images-source img { + width: 100%; + max-height: calc(100vh - 20rem); + margin: 0; + } + + .result-images-labels p span { + width: inherit; + .ltr-margin-right(1rem); + } + } +} diff --git a/client/simple/src/less/embedded.less b/client/simple/src/less/embedded.less new file mode 100644 index 000000000..bd7b89ea6 --- /dev/null +++ b/client/simple/src/less/embedded.less @@ -0,0 +1,33 @@ +iframe[src^="https://w.soundcloud.com"] { + height: 120px; +} + +iframe[src^="https://www.deezer.com"] { + // The real size is 92px, but 94px are needed to avoid an inner scrollbar of + // the embedded HTML. + height: 94px; +} + +iframe[src^="https://www.mixcloud.com"] { + // the embedded player from mixcloud has some quirks: initial there is an + // issue with an image URL that is blocked since it is an a Cross-Origin + // request. The alternative text (Mixcloud Logo then cause an + // scrollbar in the inner of the iframe we can't avoid. Another quirk comes + // when pressing the play button, sometimes the shown player has an height of + // 200px, sometimes 250px. + height: 250px; +} + +iframe[src^="https://bandcamp.com/EmbeddedPlayer"] { + // show playlist + height: 350px; +} + +iframe[src^="https://bandcamp.com/EmbeddedPlayer/track"] { + // hide playlist + height: 120px; +} + +iframe[src^="https://genius.com/songs"] { + height: 65px; +} diff --git a/client/simple/src/less/index.less b/client/simple/src/less/index.less new file mode 100644 index 000000000..8590d0c3b --- /dev/null +++ b/client/simple/src/less/index.less @@ -0,0 +1,51 @@ +#main_index { + margin-top: 26vh; +} + +.index { + text-align: center; + + .title { + background: url('../img/searxng.png') no-repeat; + min-height: 4rem; + margin: 4rem auto; + background-position: center; + background-size: contain; + } + + h1 { + font-size: 4em; + visibility: hidden; + } + + #search, + #search_header { + margin: 0 auto; + background: inherit; + border: inherit; + padding: 0; + display: block; + } + + .search_filters { + display: block; + margin: 1em 0; + } + + .category label { + padding: 6px 10px; + border-bottom: initial !important; + } +} + +@media screen and (max-width: @tablet) { + div.title { + h1 { + font-size: 1em; + } + } + + #main_index { + margin-top: 6em; + } +} diff --git a/client/simple/src/less/info.less b/client/simple/src/less/info.less new file mode 100644 index 000000000..f354135d2 --- /dev/null +++ b/client/simple/src/less/info.less @@ -0,0 +1,10 @@ +.info-page { + code { + font-family: monospace; + .rounded-corners-tiny; + background-color: var(--color-doc-code-background); + color: var(--color-doc-code); + padding: 0.2rem; + border: 0 none; + } +} diff --git a/client/simple/src/less/mixins.less b/client/simple/src/less/mixins.less new file mode 100644 index 000000000..a4bae7128 --- /dev/null +++ b/client/simple/src/less/mixins.less @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +// Mixins +.text-size-adjust (@property: 100%) { + -webkit-text-size-adjust: @property; + -ms-text-size-adjust: @property; + -moz-text-size-adjust: @property; + text-size-adjust: @property; +} + +.rounded-corners (@radius: 10px) { + border-radius: @radius; +} + +.rounded-right-corners (@radius: 0 10px 10px 0) { + border-radius: @radius; +} + +.rounded-corners-tiny (@radius: 5px) { + border-radius: @radius; +} + +// disable user selection +.disable-user-select () { + -webkit-touch-callout: none; + user-select: none; +} + +.show-content-button() { + padding: 5px 10px; + .rounded-corners-tiny; + background: var(--color-show-btn-background); + color: var(--color-show-btn-font); + cursor: pointer; + + &:hover { + background: var(--color-btn-background); + color: var(--color-btn-font); + } +} diff --git a/client/simple/src/less/new_issue.less b/client/simple/src/less/new_issue.less new file mode 100644 index 000000000..e10a2791c --- /dev/null +++ b/client/simple/src/less/new_issue.less @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +.stats_endpoint { + .github-issue-button { + display: block; + font-size: 16px; + } + + .issue-hide { + display: none; + } + + input[type=checked] { + position: absolute; + } + + label { + margin: 1rem 1rem 1rem 0; + } + + .step_content { + margin: 1rem 1rem 1rem 2rem; + } + + .step1, + .step2 { + visibility: hidden; + } + + .step1_delay { + transition: visibility 0s linear 4s; + } + + #step1:checked ~ .step1, + #step2:checked ~ .step2 { + visibility: visible; + } +} diff --git a/client/simple/src/less/preferences.less b/client/simple/src/less/preferences.less new file mode 100644 index 000000000..497b2077a --- /dev/null +++ b/client/simple/src/less/preferences.less @@ -0,0 +1,233 @@ +table { + border-collapse: collapse; + + th, + td { + text-align: center; + padding: 1rem 0.5rem; + .ltr-text-align-left(); + } + + tr.pref-group th { + font-weight: normal; + .ltr-text-align-left(); + background: var(--color-settings-table-group-background); + } +} + +#main_preferences { + form { + width: 100%; + } + + fieldset { + margin: 8px; + border: none; + } + + legend { + margin: 0; + padding: 5px 0 0 0; + display: block; + .ltr-float-left(); + width: 300px; + } + + input[type="text"] { + width: 13.25rem; + color: var(--color-toolkit-input-text-font); + border: none; + background: none repeat scroll 0 0 var(--color-toolkit-select-background); + padding: 0.2rem 0.4rem; + height: 2rem; + .rounded-corners-tiny; + + &:hover, + &:focus { + background-color: var(--color-toolkit-select-background-hover); + } + } + + div.pref-group { + width: 100%; + font-weight: normal; + padding: 1rem 0.5rem; + .ltr-text-align-left(); + background: var(--color-settings-table-group-background); + } + + .value { + margin: 0; + padding: 0; + .ltr-float-left(); + width: 15em; + + select, + input[type="text"] { + font-size: inherit !important; + margin-top: 0; + .ltr-margin-right(1rem); + margin-bottom: 0; + .ltr-margin-left(0); + } + + select { + width: 14rem; + } + + select:focus, + input:focus { + outline: none; + box-shadow: 0 0 1px 1px var(--color-btn-background); + } + } + + .description { + margin: 0; + padding: 5px 0 0 0; + .ltr-float-right(); + width: 50%; + color: var(--color-settings-engine-description-font); + font-size: 90%; + } + + .bang { + .ltr-text-align-left(); + .rounded-corners-tiny; + background-color: var(--color-doc-code-background); + color: var(--color-doc-code); + padding: 0.2rem; + border: 0 none; + } + + .category { + .ltr-margin-right(0.5rem); + + label { + border: 2px solid transparent; + padding: 0.2rem 0.4rem; + .rounded-corners-tiny; + } + } + + .category input[type="checkbox"]:checked + label { + border: 2px solid var(--color-categories-item-border-selected); + } + + table.table_engines { + th.name { + /* stylelint-disable */ + label { + cursor: pointer; + } + /* stylelint-enable */ + + .engine-tooltip { + margin-top: 1.8rem; + .ltr-left(calc((100% - 85em) / 2 + 10em)); + max-width: 40rem; + + .engine-description { + margin-top: 0.5rem; + } + + .bang { + margin: 0.3rem; + } + } + } + + .checkbox-col, + .name, + .shortcut { + .ltr-text-align-left(); + } + } + + table.cookies { + width: 100%; + direction: ltr; + + th, + td { + text-align: left; + font-family: monospace; + font-size: 1rem; + padding: 0.5em; + vertical-align: top; + } + + td:first-child { + word-break: keep-all; + width: 14rem; + padding-right: 1rem; + } + + td:last-child { + word-break: break-all; + } + + & > tbody > tr:nth-child(even) > th, + & > tbody > tr:nth-child(even) > td { + background-color: var(--color-settings-tr-hover); + } + } + + .preferences_back { + background: none repeat scroll 0 0 var(--color-btn-background); + color: var(--color-btn-font); + border: 0 none; + .rounded-corners; + + cursor: pointer; + display: inline-block; + margin: 2px 4px; + padding: 0.7em; + + a { + color: var(--color-settings-return-font); + } + + a::first-letter { + text-transform: uppercase; + } + } + + #toggle-all-engines-container { + width: max-content; + margin-left: auto; + } + + div.selectable_url { + pre { + width: 100%; + } + } + + #copy-hash-container { + display: flex; + align-items: center; + gap: 0.5rem; + + div.selectable_url { + pre { + width: auto; + flex-grow: 1; + } + } + } + + #pref-hash-input { + width: 100%; + } +} + +@media screen and (max-width: @tablet) { + .preferences_back { + clear: both; + } + + .engine-tooltip { + .ltr-left(10em) !important; + } +} diff --git a/client/simple/src/less/result_templates.less b/client/simple/src/less/result_templates.less new file mode 100644 index 000000000..afabdf322 --- /dev/null +++ b/client/simple/src/less/result_templates.less @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +.osm-map-box { + height: 300px; + width: 100%; + margin: 10px 0; +} diff --git a/client/simple/src/less/rss.less b/client/simple/src/less/rss.less new file mode 100644 index 000000000..0bc6622e3 --- /dev/null +++ b/client/simple/src/less/rss.less @@ -0,0 +1,45 @@ +@import (inline) "../../node_modules/normalize.css/normalize.css"; +@import "definitions.less"; + +.text-size-adjust (@property: 100%) { + -webkit-text-size-adjust: @property; + -ms-text-size-adjust: @property; + -moz-text-size-adjust: @property; + text-size-adjust: @property; +} + +// Reset padding and margin +html, +body, +main { + padding: 0; + margin: 0; +} + +html { + font-family: sans-serif; + font-size: 0.9em; + .text-size-adjust; + + color: var(--color-base-font); + background-color: var(--color-base-background); + + scroll-behavior: smooth; +} + +body { + margin-inline: 1rem; +} + +a { + text-decoration: none; + color: var(--color-url-font); + + &:visited { + color: var(--color-url-visited-font); + + .highlight { + color: var(--color-url-visited-font); + } + } +} diff --git a/client/simple/src/less/search.less b/client/simple/src/less/search.less new file mode 100644 index 000000000..a46e4bf06 --- /dev/null +++ b/client/simple/src/less/search.less @@ -0,0 +1,393 @@ +/* +* SearXNG, A privacy-respecting, hackable metasearch engine +*/ + +#search { + padding: 0; + margin: 0; +} + +#search_header { + padding-top: 1.5em; + .ltr-padding-right(2em); + .ltr-padding-left(@results-offset - 3rem); + margin: 0; + background: var(--color-header-background); + border-bottom: 1px solid var(--color-header-border); + display: grid; + gap: 1rem 1.2rem; + grid-template-columns: 3rem 1fr; + grid-template-areas: + "logo search" + "spacer categories"; +} + +.category_checkbox, +.category_button { + display: inline-block; + position: relative; + .ltr-margin-right(1rem); + padding: 0; +} + +.category_checkbox { + input { + display: none; + } + + label { + svg { + padding-right: 0.2rem; + } + + cursor: pointer; + padding: 0.2rem 0; + display: inline-flex; + text-transform: capitalize; + font-size: 0.9em; + border-bottom: 2px solid transparent; + .disable-user-select; + + div.category_name { + margin: auto 0; + } + } + + input[type="checkbox"]:checked + label { + color: var(--color-categories-item-selected-font); + border-bottom: 2px solid var(--color-categories-item-border-selected); + } +} + +button.category_button { + background-color: inherit; + color: var(--color-base-font); + cursor: pointer; + padding: 0.2rem 0; + display: inline-flex; + align-items: center; + text-transform: capitalize; + font-size: 0.9em; + border: none; + border-bottom: 2px solid transparent; + + svg { + padding-right: 0.2rem; + } + + &.selected, + &:active { + color: var(--color-categories-item-selected-font); + border-bottom: 2px solid var(--color-categories-item-border-selected); + } +} + +// only used when JavaScript is disabled +.no-js #categories_container:has(button.category_button:focus-within) button.category_button { + &.selected { + color: var(--color-base-font); + border-bottom: none; + } + + &:focus-within { + color: var(--color-categories-item-selected-font); + border-bottom: 2px solid var(--color-categories-item-border-selected); + } +} + +#search_logo { + padding: 0.5rem 10px 0 10px; + grid-area: logo; + display: flex; + align-items: center; + justify-content: center; + + svg { + flex: 1; + width: 30px; + height: 30px; + margin: 0.5rem 0 auto 0; + } +} + +.search_categories { + grid-area: categories; + + .help { + display: none; + } + + &:hover .help { + display: block; + position: absolute; + background: var(--color-base-background); + padding: 1rem 0.6rem 0.6rem 0; + z-index: 1000; + width: 100%; + left: -0.1rem; + } +} + +#search_view { + padding: 0.5rem 0.3rem 0 0.5rem; + grid-area: search; + + body.results_endpoint & { + padding: 0.5rem 2.8rem 0 0; + } +} + +.search_box { + border-radius: 0.8rem; + width: @search-width; + display: inline-flex; + flex-direction: row; + white-space: nowrap; + box-shadow: var(--color-search-shadow); +} + +#clear_search { + display: block; + border-collapse: separate; + box-sizing: border-box; + width: 1.8rem; + margin: 0; + padding: 0.8rem 0.2rem; + background: none repeat scroll 0 0 var(--color-search-background); + border: none; + outline: none; + color: var(--color-search-font); + font-size: 1.1rem; + z-index: 1000; + + &:hover { + color: var(--color-search-background-hover); + } + + &.empty * { + display: none; + } +} + +html.no-js #clear_search.hide_if_nojs { + display: none; +} + +#q, +#send_search { + display: block; + margin: 0; + padding: 0.8rem; + background: none repeat scroll 0 0 var(--color-search-background); + border: none; + outline: none; + color: var(--color-search-font); + font-size: 1.1rem; + z-index: 100; +} + +#q { + width: 100%; + .ltr-padding-left(1rem); + .ltr-padding-right(0) !important; + .ltr-rounded-left-corners(0.8rem); +} + +#q::-ms-clear, +#q::-webkit-search-cancel-button { + display: none; +} + +#send_search { + .ltr-rounded-right-corners(0.8rem); + + &:hover { + cursor: pointer; + background-color: var(--color-search-background-hover); + color: var(--color-search-background); + } +} + +.no-js #clear_search, +.no-js #send_search { + width: auto !important; + .ltr-border-left(1px solid var(--color-search-border)); +} + +.search_filters { + margin-top: 0.6rem; + .ltr-margin-right(0); + margin-bottom: 0; + .ltr-margin-left(@results-offset + 0.6rem); + display: flex; + overflow-x: auto; + overscroll-behavior-inline: contain; + + select { + background-color: inherit; + + &:hover, + &:focus { + color: var(--color-base-font); + } + } +} + +@media screen and (max-width: @tablet) { + #search_header { + padding: 1.5em @results-tablet-offset 0 @results-tablet-offset; + column-gap: @results-tablet-offset; + } + + .search_filters { + margin-top: 0.6rem; + .ltr-margin-right(0); + margin-bottom: 0; + .ltr-margin-left(@results-tablet-offset + 3rem); + } + + #categories { + font-size: 90%; + clear: both; + } +} + +@media screen and (max-width: @tablet) and (hover: none) { + #main_index, + #main_results { + #categories_container { + width: max-content; + + .category_checkbox { + display: inline-block; + width: auto; + } + } + + #categories { + width: 100%; + .ltr-text-align-left(); + overflow: scroll hidden; + -webkit-overflow-scrolling: touch; + } + } +} + +@media screen and (max-width: @phone) { + #search_header { + width: 100%; + margin: 0; + padding: 0.1rem 0 0 0; + gap: 0 0; + grid-template-areas: + "logo search" + "categories categories"; + } + + .search_logo { + padding: 0; + } + + .search_box { + width: 98%; + display: flex; + } + + #q { + width: 100%; + flex: 1; + } + + .search_filters { + margin: 0 10px; + padding: 0.5rem 0; + } + + .category { + display: inline-block; + width: auto; + margin: 0; + + svg { + display: none; + } + } + + .category_checkbox { + label { + padding: 1rem !important; + margin: 0 !important; + } + } + + .category_button { + padding: 1rem !important; + margin: 0 !important; + } + + #search_view:focus-within { + display: block; + background-color: var(--color-search-background); + position: absolute; + top: 0; + height: 100%; + width: 100%; + z-index: 2000; + + .search_box { + border-bottom: 1px solid var(--color-search-border); + width: 100%; + border-radius: 0; + box-shadow: none; + + #send_search { + .ltr-margin-right(0) !important; // Delete when send_search button is disabled on mobile. + } + + * { + border: none; + border-radius: 0; + box-shadow: none; + } + } + } + + #main_results #q:placeholder-shown ~ #send_search { + .ltr-margin-right(2.6rem); + transition: margin 0.1s; + } +} + +@media screen and (max-width: @ultra-small-phone) { + #search_header { + grid-template-areas: + "search search" + "categories categories"; + } + + #search_logo { + display: none; + } +} + +#categories { + .disable-user-select; + + &::-webkit-scrollbar { + width: 0; + height: 0; + } +} + +#categories_container { + position: relative; +} + +.favicon img { + height: 1.5rem; + width: 1.5rem; + border-radius: 10%; + background-color: var(--color-favicon-background-color); + border: 1px solid var(--color-favicon-border-color); + display: flex; +} diff --git a/client/simple/src/less/stats.less b/client/simple/src/less/stats.less new file mode 100644 index 000000000..1e823f7c9 --- /dev/null +++ b/client/simple/src/less/stats.less @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +.engine-stats { + border-spacing: 0; + border-collapse: collapse; + + tr td, + tr th { + border-bottom: 1px solid var(--color-result-border); + padding: 0.25rem; + } + + table.engine-tooltip { + border-spacing: 0; + border-collapse: collapse; + + td, + th { + border: none; + } + } + + .engine-name { + width: 20rem; + } + + .engine-score { + width: 7rem; + text-align: right; + } + + .engine-reliability { + text-align: right; + } +} + +table.engine-error th.engine-error-type, +table.engine-error td.engine-error-type, +failed-test { + width: 10rem; +} + +.engine-errors { + margin-top: 3rem; + + table.engine-error { + max-width: 1280px; + margin: 1rem 0 3rem 0; + border: 1px solid var(--color-result-border); + .ltr-text-align-left(); + + tr th, + tr td { + padding: 0.5rem; + } + + & span.log_parameters { + border-right: 1px solid solid var(--color-result-border); + padding: 0 1rem 0 0; + margin: 0 0 0 0.5rem; + } + } +} + +.bar-chart-value { + width: 3em; + display: inline-block; + text-align: right; + padding-right: 0.5rem; +} + +.bar-chart-graph { + width: calc(100% - 5rem); + display: inline-block; +} + +.bar-chart-bar { + border: 3px solid var(--color-bar-chart-primary); + margin: 1px 0; +} + +.bar-chart-serie1 { + border: 3px solid var(--color-bar-chart-primary); + margin: 1px 0; + float: left; +} + +.bar-chart-serie2 { + border: 3px solid var(--color-bar-chart-secondary); + margin: 1px 0; + float: left; +} + +.bar0 { + width: 0; + border: 0; +} + +.generate-bar(100); + +.generate-bar(@n, @i: 1) when (@i =< @n) { + .bar@{i} { + width: (@i * 100% / @n); + } + .generate-bar(@n, (@i + 1)); +} diff --git a/client/simple/src/less/style-center.less b/client/simple/src/less/style-center.less new file mode 100644 index 000000000..3618bed86 --- /dev/null +++ b/client/simple/src/less/style-center.less @@ -0,0 +1,118 @@ +/* +--center-page-width overrides the less variable @results-width when the results are centered +see the CSS rules for #results in style.less ( grid-template-columns and gap). + +In this file, the --center-page-width values comes from the Oscar theme (Bootstrap 3). + +All rules starts with ".center-alignment-yes #main_results" to be enabled only +on the /search URL and when the "center alignment" preference is enabled. +*/ + +@media screen and (min-width: @phone) { + .center-alignment-yes #main_results { + --center-page-width: 48rem; + } +} + +@media screen and (width >= 62rem) { + .center-alignment-yes #main_results { + --center-page-width: 60rem; + } +} + +@media screen and (min-width: @tablet) { + .center-alignment-yes #main_results { + --center-page-width: 73rem; + } +} + +@media screen and (min-width: @phone) and (max-width: @tablet) { + // any change must be reset in @media screen and (min-width: @tablet) { ... } + .center-alignment-yes #main_results { + #results { + grid-template-columns: 60% calc(40% - @results-gap); + margin-left: 0; + margin-right: 0; + } + + #urls { + .ltr-margin-left(3rem); + } + + #sidebar { + .ltr-margin-right(1rem); + } + + #backToTop { + .ltr-left(calc(60% + 1rem)); + } + } +} + +@media screen and (min-width: @tablet) { + .center-alignment-yes #main_results { + display: flex; + flex-direction: column; + align-items: center; + + #search { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + } + + #search_header { + grid-template-columns: calc(50% - 4.5rem - var(--center-page-width) / 2) 3rem var(--center-page-width); + grid-template-areas: "na logo search" "na spacer categories"; + column-gap: 1.2rem; // from search.less + width: 100%; + padding-left: 0; + padding-right: 0; + } + + .search_filters { + .ltr-margin-left(0.5rem); + width: var(--center-page-width); + } + + #results { + // from style.less (when screen width = @tablet, reset layout from tablet) + .ltr-margin-right(2rem); + .ltr-margin-left(@results-offset); + // + + &.only_template_images, + &.image-detail-open { + // * grid-template-columns and .ltr-margin-left are set in style.less + // * With .image-detail-open.only_template_images, the width is set in detail.less + // * #results is going to be centered because of the #main_results rules, + // align-self aligns the results on the left or right according to the language. + align-self: flex-start; + } + + &:not(.only_template_images, .image-detail-open) { + // the gap is set in style.less + .ltr-margin-left(1.5rem); + grid-template-columns: calc(var(--center-page-width) - @results-gap - @results-sidebar-width) @results-sidebar-width; + + #backToTop { + .ltr-left(calc(50% - @results-sidebar-width - @results-gap + 1rem + var(--center-page-width) / 2)); + } + } + + .result .content { + max-width: inherit; + } + } + + // from style.less (when screen width = @tablet, reset layout from tablet) + #urls { + .ltr-margin-left(0); + } + + #sidebar { + .ltr-margin-right(0); + } + } +} diff --git a/client/simple/src/less/style-ltr.less b/client/simple/src/less/style-ltr.less new file mode 100644 index 000000000..6f7218b02 --- /dev/null +++ b/client/simple/src/less/style-ltr.less @@ -0,0 +1,85 @@ +.ltr-left(@offset) { + left: @offset; +} + +.ltr-right(@offset) { + right: @offset; +} + +.ltr-margin-right(@offset) { + margin-right: @offset; +} + +.ltr-margin-left(@offset) { + margin-left: @offset; +} + +.ltr-border-right(@offset) { + border-right: @offset; +} + +.ltr-border-left(@offset) { + border-left: @offset; +} + +.ltr-padding-right(@offset) { + padding-right: @offset; +} + +.ltr-padding-left(@offset) { + padding-left: @offset; +} + +.ltr-float-left() { + float: left; +} + +.ltr-float-right() { + float: right; +} + +.ltr-text-align-right() { + text-align: right; +} + +.ltr-rounded-left-corners(@radius) { + border-radius: @radius 0 0 @radius; +} + +.ltr-rounded-top-left-corners(@radius) { + border-radius: @radius 0 0 0; +} + +.ltr-rounded-bottom-left-corners(@radius) { + border-radius: 0 0 0 @radius; +} + +.ltr-rounded-right-corners(@radius) { + border-radius: 0 @radius @radius 0; +} + +.ltr-rounded-top-right-corners(@radius) { + border-radius: 0 @radius 0 0; +} + +.ltr-rounded-bottom-right-corners(@radius) { + border-radius: 0 0 @radius 0; +} + +.ltr-text-align-left() { + text-align: left; +} + +.ltr-border-left-width(@offset) { + border-left-width: @offset; +} + +.ltr-border-right-width(@offset) { + border-right-width: @offset; +} + +.ltr-transform() { + transform: scale(1, 1); +} + +@import "style.less"; diff --git a/client/simple/src/less/style-rtl.less b/client/simple/src/less/style-rtl.less new file mode 100644 index 000000000..8e2634d34 --- /dev/null +++ b/client/simple/src/less/style-rtl.less @@ -0,0 +1,159 @@ +.ltr-left(@offset) { + right: @offset; +} + +.ltr-right(@offset) { + left: @offset; +} + +.ltr-margin-right(@offset) { + margin-left: @offset; +} + +.ltr-margin-left(@offset) { + margin-right: @offset; +} + +.ltr-border-right(@offset) { + border-left: @offset; +} + +.ltr-border-left(@offset) { + border-right: @offset; +} + +.ltr-padding-right(@offset) { + padding-left: @offset; +} + +.ltr-padding-left(@offset) { + padding-right: @offset; +} + +.ltr-float-left() { + float: right; +} + +.ltr-float-right() { + float: left; +} + +.ltr-text-align-right() { + text-align: left; +} + +.ltr-rounded-left-corners(@radius) { + border-radius: 0 @radius @radius 0; +} + +.ltr-rounded-top-left-corners(@radius) { + border-radius: 0 @radius 0 0; +} + +.ltr-rounded-bottom-left-corners(@radius) { + border-radius: 0 0 @radius 0; +} + +.ltr-rounded-right-corners(@radius) { + border-radius: @radius 0 0 @radius; +} + +.ltr-rounded-top-right-corners(@radius) { + border-radius: @radius 0 0 0; +} + +.ltr-rounded-bottom-right-corners(@radius) { + border-radius: 0 0 0 @radius; +} + +.ltr-text-align-left() { + text-align: right; +} + +.ltr-border-left-width(@offset) { + border-right-width: @offset; +} + +.ltr-border-right-width(@offset) { + border-left-width: @offset; +} + +.ltr-transform() { + transform: scale(-1, 1); +} + +@import "style.less"; + +#q, +#sidebar .infobox dt bdi { + direction: rtl; +} + +// URL are displayed LTR but align on the right +#urls { + direction: initial; + text-align: right; + + .result .url_header { + direction: rtl; + } + + .result .url_wrapper { + justify-content: end; + } +} + +// Image flexbox +#main_results div#results.only_template_images #urls { + direction: rtl; +} + +// Image detail +#results.image-detail-open article.result-images[data-vim-selected] .detail .result-images-labels p { + direction: rtl; + + &.result-url { + // Display URL using the LTR direction + direction: ltr; + + span { + // And put the label on the right + direction: rtl; + float: right; + } + } +} + +// select HTML element +@supports ((background-position-x: 100%) and ((appearance: none) or (-webkit-appearance: none) or (-moz-appearance: none))) { + select { + border-width: 0 0 0 2rem; + background-position-x: -2rem; + } +} + +// vim hotkey helps is not translated +#vim-hotkeys-help table { + direction: ltr; + text-align: left; +} + +// Logo on the right +#main_preferences h1, +#main_stats h1 { + background-position-x: 100%; +} + +// patch of stats.less +.bar-chart-serie1, +.bar-chart-serie2 { + float: right; +} + +.engine-stats .engine-name, +.engine-stats .engine-score, +.engine-stats .result-count, +.engine-stats .response-time, +.engine-stats .engine-reliability { + text-align: right; +} diff --git a/client/simple/src/less/style.less b/client/simple/src/less/style.less new file mode 100644 index 000000000..7dca47402 --- /dev/null +++ b/client/simple/src/less/style.less @@ -0,0 +1,1162 @@ +/* +* SearXNG, A privacy-respecting, hackable metasearch engine +* +* To convert "style.less" to "style.css" run: $make styles +*/ + +// stylelint-disable no-descending-specificity + +@import (inline) "../../node_modules/normalize.css/normalize.css"; +@import "definitions.less"; +@import "mixins.less"; +@import "code.less"; +@import "toolkit.less"; +@import "autocomplete.less"; +@import "detail.less"; +@import "animations.less"; +@import "embedded.less"; +@import "info.less"; +@import "new_issue.less"; +@import "stats.less"; +@import "result_templates.less"; + +// for index.html template +@import "index.less"; + +// for preferences.html template +@import "preferences.less"; + +// Search-Field +@import "search.less"; + +// to center the results +@import "style-center.less"; + +// ion-icon +.ion-icon { + display: inline-block; + vertical-align: bottom; + line-height: 1; + text-decoration: inherit; + .ltr-transform(); +} + +.ion-icon-small { + width: 1rem; + height: 1rem; + .ion-icon; +} + +.ion-icon-big { + width: 1.5rem; + height: 1.5rem; + .ion-icon; +} + +// Main LESS-Code +html { + font-family: sans-serif; + font-size: 0.9em; + .text-size-adjust; + + color: var(--color-base-font); + background-color: var(--color-base-background); + padding: 0; + margin: 0; + + scroll-behavior: smooth; +} + +body, +main { + padding: 0; + margin: 0; +} + +body { + display: flex; + flex-direction: column; + height: 100vh; + margin: 0; +} + +main { + width: 100%; + margin-bottom: 2rem; + flex: 1; +} + +.page_with_header { + margin: 2em auto; + width: 85em; +} + +footer { + clear: both; + min-height: 4rem; + padding: 1rem 0; + width: 100%; + text-align: center; + background-color: var(--color-footer-background); + border-top: 1px solid var(--color-footer-border); + overflow: hidden; + + p { + font-size: 0.9em; + } +} + +.page_with_header .logo { + height: 40px; +} + +input[type="submit"], +#results button[type="submit"], +.button { + padding: 0.7rem; + display: inline-block; + background: var(--color-btn-background); + color: var(--color-btn-font); + .rounded-corners; + + border: 0; + cursor: pointer; +} + +a { + text-decoration: none; + color: var(--color-url-font); + + &:visited { + color: var(--color-url-visited-font); + + .highlight { + color: var(--color-url-visited-font); + } + } +} + +article[data-vim-selected] { + background: var(--color-result-vim-selected); + .ltr-border-left(0.2rem solid var(--color-result-vim-arrow)); + .ltr-rounded-right-corners(10px); +} + +article.result-images[data-vim-selected] { + background: var(--color-result-vim-arrow); + border: none; + .rounded-corners; + + .image_thumbnail { + filter: opacity(60%); + } + + span.title, + span.source { + color: var(--color-result-image-span-font-selected); + } +} + +article[data-vim-selected].category-videos, +article[data-vim-selected].category-news, +article[data-vim-selected].category-map, +article[data-vim-selected].category-music, +article[data-vim-selected].category-files, +article[data-vim-selected].category-social { + border: 1px solid var(--color-result-vim-arrow); + .rounded-corners; +} + +.result { + margin: @results-margin 0; + padding: @result-padding; + box-sizing: border-box; + width: 100%; + .ltr-border-left(0.2rem solid transparent); + + h3 { + font-size: 1.2rem; + word-wrap: break-word; + margin: 0.4rem 0 0.4rem 0; + padding: 0; + + a { + color: var(--color-result-link-font); + font-weight: normal; + font-size: 1.1em; + + &:visited { + color: var(--color-result-link-visited-font); + } + + &:focus, + &:hover { + text-decoration: underline; + border: none; + outline: none; + } + } + } + + .cache_link, + .proxyfied_link { + font-size: smaller !important; + margin-left: 0.5rem; + } + + .content, + .stat { + font-size: 0.9em; + margin: 0; + padding: 0; + max-width: 54em; + word-wrap: break-word; + line-height: 1.24; + + .highlight { + color: var(--color-result-description-highlight-font); + background: inherit; + font-weight: bold; + } + } + + .altlink a { + font-size: 0.9em; + margin: 0 10px 0 0; + .show-content-button; + } + + .codelines { + .highlight { + color: inherit; + background: inherit; + font-weight: normal; + } + } + + .url_header { + display: flex; + gap: 0.5rem; + } + + .url_wrapper { + display: flex; + align-items: center; + font-size: 1rem; + color: var(--color-result-url-font); + flex-flow: row nowrap; + overflow: hidden; + margin: 0; + padding: 0; + + .url_o1 { + white-space: nowrap; + flex-shrink: 1; + padding-bottom: 1px; + + .url_i1 { + unicode-bidi: plaintext; + } + } + + .url_o1::after { + content: " "; + width: 1ch; + display: inline-block; + } + + .url_o2 { + overflow: hidden; + white-space: nowrap; + flex: 0 1 content; + text-align: right; + padding-bottom: 1px; + + .url_i2 { + float: right; + } + } + } + + .published_date, + .result_length, + .result_views, + .result_author, + .result_shipping, + .result_source_country { + font-size: 0.8em; + color: var(--color-result-publishdate-font); + } + + .result_price { + font-size: 1.2em; + color: var(--color-result-description-highlight-font); + } + + img.thumbnail { + .ltr-float-left(); + padding-top: 0.6rem; + .ltr-padding-right(1rem); + width: 7rem; + height: unset; // remove height value that was needed for lazy loading + } + + .break { + clear: both; + } +} + +.result-paper, +.result-packages { + .attributes { + display: table; + border-spacing: 0.125rem; + + div { + display: table-row; + + span { + font-size: 0.9rem; + margin-top: 0.25rem; + display: table-cell; + + time { + font-size: 0.9rem; + } + } + + span:first-child { + color: var(--color-base-font); + min-width: 10rem; + } + + span:nth-child(2) { + color: var(--color-result-publishdate-font); + } + } + } + + .content { + margin-top: 0.25rem; + } + + .comments { + font-size: 0.9rem; + margin: 0.25rem 0 0 0; + padding: 0; + word-wrap: break-word; + line-height: 1.24; + font-style: italic; + } +} + +.result-packages { + .attributes { + margin-top: 0.3rem; + } +} + +.template_group_images { + display: flex; + flex-wrap: wrap; +} + +.template_group_images::after { + flex-grow: 10; + content: ""; +} + +.category-videos, +.category-news, +.category-map, +.category-music, +.category-files, +.category-social { + border: 1px solid var(--color-result-border); + margin: 0 @results-tablet-offset 1rem @results-tablet-offset !important; + .rounded-corners; +} + +.category-social .image { + width: auto !important; + min-width: 48px; + min-height: 48px; + padding: 0 5px 25px 0 !important; +} + +.audio-control audio { + width: 100%; + padding: 10px 0 0 0; +} + +.embedded-content iframe { + width: 100%; + padding: 10px 0 0 0; +} + +.result-videos { + img.thumbnail { + .ltr-float-left(); + padding-top: 0.6rem; + .ltr-padding-right(1rem); + width: 20rem; + height: unset; // remove height value that was needed for lazy loading + } +} + +.result-videos .content { + overflow: hidden; +} + +.result-videos .embedded-video iframe { + width: 100%; + aspect-ratio: 16 / 9; + padding: 10px 0 0 0; +} + +@supports not (aspect-ratio: 1 / 1) { + // support older browsers which do not have aspect-ratio + // https://caniuse.com/?search=aspect-ratio + .result-videos .embedded-video iframe { + height: calc(@results-width * 9 / 16); + } +} + +.engines { + .ltr-float-right(); + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + color: var(--color-result-engines-font); + + span { + font-size: smaller; + margin-top: 0; + margin-bottom: 0; + .ltr-margin-right(0.5rem); + .ltr-margin-left(0); + } +} + +.small_font { + font-size: 0.8em; +} + +.highlight { + color: var(--color-result-link-font-highlight); + background: inherit; +} + +.empty_element { + font-style: italic; +} + +.result-images { + flex-grow: 1; + padding: 0.5rem 0.5rem 3rem 0.5rem; + margin: 0.25rem; + border: none !important; + height: @results-image-row-height; + width: unset; + + & > a { + position: relative; + outline: none; + } + + img { + margin: 0; + padding: 0; + border: none; + height: 100%; + width: 100%; + object-fit: cover; + vertical-align: bottom; + background: var(--color-result-image-background); + } + + .image_resolution { + position: absolute; + right: 0; + bottom: 0; + background: var(--color-image-resolution-background); + padding: 0.3rem 0.5rem; + font-size: 0.9rem; + color: var(--color-image-resolution-font); + border-top-left-radius: 0.3rem; + } + + span.title, + span.source { + display: block; + position: absolute; + + width: 100%; + font-size: 0.9rem; + color: var(--color-result-image-span-font); + padding: 0.5rem 0 0 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + span.source { + padding: 1.8rem 0 0 0; + font-size: 0.7rem; + } +} + +.result-map { + img.image { + .ltr-float-right() !important; + height: 100px !important; + width: auto !important; + } + + table { + font-size: 0.9em; + width: auto; + border-collapse: separate; + border-spacing: 0 0.35rem; + + th { + font-weight: inherit; + width: 17rem; + vertical-align: top; + .ltr-text-align-left(); + } + + td { + vertical-align: top; + .ltr-text-align-left(); + } + } +} + +.hidden { + display: none !important; +} + +#results { + margin-top: 1rem; + .ltr-margin-right(2rem); + margin-bottom: 0; + .ltr-margin-left(@results-offset); + display: grid; + grid-template: + "corrections sidebar" min-content + "answers sidebar" min-content + "urls sidebar" 1fr + "pagination sidebar" min-content + / @results-width @results-sidebar-width + ; + gap: 0 @results-gap; +} + +#results #sidebar *:first-child { + margin-top: 0; +} + +#urls { + padding: 0; + grid-area: urls; +} + +#apis .wrapper { + display: flex; +} + +#suggestions { + .wrapper { + display: flex; + flex-flow: column; + justify-content: flex-end; + + form { + display: inline-block; + flex: 1 1 50%; + } + } +} + +#suggestions, +#infoboxes { + input { + padding: 0; + margin: 3px; + font-size: 0.9em; + display: inline-block; + background: transparent; + color: var(--color-result-search-url-font); + cursor: pointer; + width: calc(100%); + text-overflow: ellipsis; + overflow: hidden; + text-align: left; + } + + input[type="submit"], + .infobox .url a { + color: var(--color-result-link-font); + text-decoration: none; + font-size: 0.9rem; + + &:hover { + text-decoration: underline; + } + } +} + +#corrections { + grid-area: corrections; + display: flex; + flex-flow: row wrap; + margin: 0 0 1em 0; + + h4, + input[type="submit"] { + display: inline-block; + padding: 0.5rem; + margin: 0.5rem; + } + + input[type="submit"] { + font-size: 0.8rem; + .rounded-corners-tiny; + } +} + +#infoboxes .title, +#suggestions .title, +#search_url .title, +#engines_msg .title, +#apis .title { + margin: 2em 0 0.5em 0; + color: var(--color-base-font); +} + +summary.title { + cursor: pointer; + padding-top: 1em; +} + +.sidebar-collapsible { + border-top: 1px solid var(--color-sidebar-border); + padding-bottom: 0.5em; +} + +#sidebar-end-collapsible { + border-bottom: 1px solid var(--color-sidebar-border); + width: 100%; +} + +#answers { + grid-area: answers; + background: var(--color-answer-background); + padding: @result-padding; + margin: 1rem 0; + margin-top: 0; + color: var(--color-answer-font); + .rounded-corners; + + h4 { + display: none; + } + + span { + overflow-wrap: anywhere; + } + + .answer { + display: flex; + flex-direction: column; + } + + .answer-url { + margin: 5px 10px 10px auto; + } +} + +#infoboxes { + form { + min-width: 210px; + } +} + +#sidebar { + grid-area: sidebar; + word-wrap: break-word; + color: var(--color-sidebar-font); + + .infobox { + margin: 10px 0 10px; + border: 1px solid var(--color-sidebar-border); + padding: 1rem; + font-size: 0.9em; + .rounded-corners; + + h2 { + margin: 0 0 0.5em 0; + } + + img { + max-width: 100%; + max-height: 12em; + display: block; + margin: 0 auto; + padding: 0; + } + + dt { + font-weight: bold; + } + + .attributes { + dl { + margin: 0.5em 0; + } + + dt { + display: inline; + margin-top: 0.5em; + .ltr-margin-right(0.25em); + margin-bottom: 0.5em; + .ltr-margin-left(0); + padding: 0; + } + + dd { + display: inline; + margin: 0.5em 0; + padding: 0; + } + } + + input { + font-size: 1em; + } + + br { + clear: both; + } + + .attributes, + .urls { + clear: both; + } + } +} + +#apis { + input { + font-size: 0.9em; + margin: 0 10px 0 0; + .show-content-button; + } +} + +#engines_msg { + .engine-name { + width: 10rem; + } + + .response-error { + color: var(--color-error); + } + + .bar-chart-value { + width: auto; + } +} + +#search_url { + div.selectable_url { + pre { + float: left; + width: 200em; + } + } + + button#copy_url { + float: right; + padding: 0.4rem; + margin-left: 0.5rem; + border-radius: 0.3rem; + display: none; // will be shown by JS. + } +} + +#links_on_top { + position: absolute; + .ltr-right(1rem); + .ltr-text-align-right(); + top: 2.7rem; + padding: 0; + border: 0; + display: flex; + align-items: center; + font-size: 1em; + color: var(--color-search-font); + + a { + display: flex; + align-items: center; + margin-left: 1em; + + svg { + font-size: 1.2em; + .ltr-margin-right(0.125em); + } + } + + a, + a:link *, + a:hover *, + a:visited *, + a:active * { + color: var(--color-search-font); + } +} + +#pagination { + grid-area: pagination; + + br { + clear: both; + } +} + +.numbered_pagination { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + overflow: hidden; +} + +.page_number { + background: transparent !important; + color: var(--color-result-link-font) !important; + text-decoration: underline; +} + +.page_number_current { + background: transparent; + color: var(--color-result-link-visited-font); + border: none; +} + +#backToTop { + border: 1px solid var(--color-backtotop-border); + margin: 0; + padding: 0; + font-size: 1em; + background: var(--color-backtotop-background); + position: fixed; + bottom: 8rem; + .ltr-left(@results-width + @results-offset + (0.5 * @results-gap - 1.2em)); + transition: opacity 0.5s; + opacity: 0; + pointer-events: none; + .rounded-corners; + + a { + display: block; + margin: 0; + padding: 0.7em; + } + + a, + a:visited, + a:hover, + a:active { + color: var(--color-backtotop-font); + } +} + +#results.scrolling #backToTop { + opacity: 1; + pointer-events: all; +} + +/* + tablet layout +*/ + +.results-tablet() { + #links_on_top { + span { + display: none; + } + } + + .page_with_header { + margin: 2rem 0.5rem; + width: auto; + } + + #infoboxes { + position: inherit; + max-width: inherit; + + .infobox { + clear: both; + + img { + .ltr-float-left(); + max-width: 10em; + margin-top: 0.5em; + .ltr-margin-right(0.5em); + margin-bottom: 0.5em; + .ltr-margin-left(0); + } + } + } + + #sidebar { + margin: 0 @results-tablet-offset @results-margin @results-tablet-offset; + padding: 0; + float: none; + border: none; + width: auto; + + input { + border: 0; + } + } + + .result { + .thumbnail { + max-width: 98%; + } + + .url { + span.url { + display: block; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + width: 100%; + } + } + + .engines { + .ltr-float-right(); + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + padding: 3px 0 0 0; + } + } + + .result-images { + border-bottom: none !important; + } + + .image_result { + max-width: 98%; + + img { + max-width: 98%; + } + } + + #backToTop { + display: none; + } + + #pagination { + margin: 2rem 0 0 0 !important; + } + + #main_results div#results { + margin: 0 auto; + justify-content: center; + display: grid; + grid-template: + "corrections" min-content + "answers" min-content + "sidebar" min-content + "urls" 1fr + "pagination" min-content + / @results-width + ; + gap: 0; + } +} + +@media screen and (width <= calc(@tablet - 0.5px)) { + #links_on_top { + span { + display: none; + } + } +} + +@media screen and (width <= 52rem) { + body.results_endpoint { + #links_on_top { + .link_on_top_about, + .link_on_top_donate { + display: none; + } + } + } +} + +@media screen and (min-width: @phone) and (max-width: @tablet) { + // when .center-alignment-yes, see style-center.less + // the media query includes "min-width: @phone" + // because the phone layout includes the tablet layout unconditionally. + .center-alignment-no { + .results-tablet(); + } +} + +/* Misc */ + +#main_results div#results.only_template_images { + margin: 1rem @results-tablet-offset 0 @results-tablet-offset; + display: grid; + grid-template: + "corrections" min-content + "answers" min-content + "sidebar" min-content + "urls" 1fr + "pagination" min-content + / 100%; + gap: 0; + + #sidebar { + display: none; + } + + #urls { + margin: 0; + display: flex; + flex-wrap: wrap; + } + + #urls::after { + flex-grow: 10; + content: ""; + } + + #backToTop { + .ltr-left(auto); + .ltr-right(1rem); + } + + #pagination { + .ltr-margin-right(4rem); + } +} + +/* + phone layout +*/ + +@media screen and (max-width: @phone) { + // based on the tablet layout + .results-tablet(); + + html { + background-color: var(--color-base-background-mobile); + } + + #main_results div#results { + grid-template-columns: 100%; + margin: 0 auto; + } + + #links_on_top { + top: 1.4rem; + .ltr-right(10px); + } + + #main_index #links_on_top { + top: 0.5rem; + .ltr-right(0.5rem); + } + + #results { + margin: 0; + padding: 0; + } + + #pagination { + margin: 2rem 1rem 0 1rem !important; + } + + article[data-vim-selected] { + border: 1px solid var(--color-result-vim-arrow); + .rounded-corners; + } + + .result { + background: var(--color-result-background); + border: 1px solid var(--color-result-background); + margin: 1rem 2%; + width: 96%; + .rounded-corners; + } + + .result-images { + margin: 0; + height: @results-image-row-height-phone; + background: var(--color-base-background-mobile); + width: unset; + } + + .infobox { + border: none !important; + background-color: var(--color-sidebar-background); + } + + .numbered_pagination { + display: none; + } + + .result-paper, + .result-packages { + .attributes { + display: block; + + div { + display: block; + + span { + display: inline; + } + + span:first-child { + font-weight: bold; + } + + span:nth-child(2) { + .ltr-margin-left(0.5rem); + } + } + } + } +} + +/* + small-phone layout +*/ + +@media screen and (max-width: @small-phone) { + .result-videos { + img.thumbnail { + float: none !important; + } + + .content { + overflow: inherit; + } + } +} + +pre code { + white-space: pre-wrap; +} diff --git a/client/simple/src/less/toolkit.less b/client/simple/src/less/toolkit.less new file mode 100644 index 000000000..d3fb2273b --- /dev/null +++ b/client/simple/src/less/toolkit.less @@ -0,0 +1,646 @@ +// other solution : http://stackoverflow.com/questions/1577598/how-to-hide-parts-of-html-when-javascript-is-disabled/13857783#13857783 + +// stylelint-disable no-descending-specificity + +html.no-js .hide_if_nojs { + display: none; +} + +html.js .show_if_nojs { + display: none; +} + +.center { + text-align: center; +} + +.right { + float: right; +} + +.left { + float: left; +} + +.invisible { + display: none !important; +} + +.list-unstyled { + list-style-type: none; + + li { + margin-top: 4px; + margin-bottom: 4px; + } +} + +.danger { + background-color: var(--color-error-background); +} + +.warning { + background: var(--color-warning-background); +} + +.success { + background: var(--color-success-background); +} + +.badge { + display: inline-block; + color: var(--color-toolkit-badge-font); + background-color: var(--color-toolkit-badge-background); + text-align: center; + white-space: nowrap; + vertical-align: baseline; + min-width: 10px; + padding: 1px 5px; + border-radius: 5px; +} + +// kbd +kbd { + padding: 2px 4px; + margin: 1px; + font-size: 90%; + color: var(--color-toolkit-kbd-font); + background: var(--color-toolkit-kbd-background); +} + +// table +table { + width: 100%; + + &.striped { + tr { + border-bottom: 1px solid var(--color-settings-tr-hover); + } + } +} + +th { + padding: 0.4em; +} + +td { + padding: 0 4px; +} + +tr { + &:hover { + background: var(--color-settings-tr-hover) !important; + } +} + +// pre +.pre() { + display: block; + font-size: 0.8em; + word-break: break-all; + margin: 0.1em; + user-select: all; +} + +div.selectable_url { + display: block; + border: 1px solid var(--color-result-search-url-border); + padding: 4px; + color: var(--color-result-search-url-font); + margin: 0.1em; + overflow: hidden; + height: 1.2em; + line-height: 1.2em; + .rounded-corners-tiny; + + pre { + .pre(); + } +} + +// dialog +.dialog() { + position: relative; + display: flex; + padding: 1rem; + margin: 0 0 1em 0; + border: 1px solid var(--color-toolkit-dialog-border); + .ltr-text-align-left(); + .rounded-corners; + + .close { + .ltr-float-right(); + position: relative; + top: -3px; + color: inherit; + font-size: 1.5em; + } + + ul, + ol, + p { + margin: 1px 0 0 0; + } + + table { + width: auto; + } + + tr { + vertical-align: text-top; + + &:hover { + background: transparent !important; + } + } + + td { + padding: 0 1em 0 0; + padding-top: 0; + .ltr-padding-right(1rem); + padding-bottom: 0; + .ltr-padding-left(0); + } + + h4 { + margin-top: 0.3em; + margin-bottom: 0.3em; + } +} + +.dialog-error { + .dialog(); + + color: var(--color-error); + background: var(--color-error-background); + border-color: var(--color-error); +} + +.dialog-error-block { + .dialog(); + + display: block; + color: var(--color-error); + background: var(--color-error-background); + border-color: var(--color-error); +} + +.dialog-warning { + .dialog(); + + color: var(--color-warning); + background: var(--color-warning-background); + border-color: var(--color-warning); +} + +.dialog-modal { + .dialog(); + + display: block; + background: var(--color-toolkit-dialog-background); + position: fixed; + top: 50%; + left: 50%; + margin: 0 auto; + transform: translate(-50%, -50%); + z-index: 5000; + + h3 { + margin-top: 0; + } +} + +// btn-collapse +.btn-collapse { + cursor: pointer; +} + +// +.scrollx { + overflow: auto hidden; + display: block; + padding: 0; + margin: 0; + border: none; +} + +/* -- tabs -- */ +.tabs .tabs > label { + font-size: 90%; +} + +ul.tabs { + border-bottom: 1px solid var(--color-toolkit-tabs-section-border); + list-style: none; + padding-left: 0; + + li { + display: flex; + } +} + +.tabs { + display: flex; + flex-wrap: wrap; + width: 100%; + min-width: 100%; + + & > * { + order: 2; + } + + & > input[type=radio] { + display: none; + } + + & > label, + & > li > a { + order: 1; + padding: 0.7em; + margin: 0 0.7em; + letter-spacing: 0.5px; + text-transform: uppercase; + border: solid var(--color-toolkit-tabs-label-border); + border-width: 0 0 2px 0; + color: unset; + + .disable-user-select(); + + cursor: pointer; + + &.active { + border-bottom: 2px solid var(--color-categories-item-border-selected); + background: var(--color-categories-item-selected); + color: var(--color-categories-item-selected-font); + } + } + + & > label:hover, + & > li > a:hover { + border-bottom: 2px solid var(--color-categories-item-border-selected); + } + + & > section { + min-width: 100%; + padding: 0.7rem 0; + box-sizing: border-box; + border-top: 1px solid var(--color-toolkit-tabs-section-border); + display: none; + } + + // default selection + & > label:last-of-type { + border-bottom: 2px solid var(--color-categories-item-border-selected); + background: var(--color-categories-item-selected); + color: var(--color-categories-item-selected-font); + letter-spacing: -0.1px; + } + + & > section:last-of-type { + display: block; + } +} + +html body .tabs > input:checked { + ~ section { + display: none; + } + + ~ label { + position: inherited; + background: inherit; + border-bottom: 2px solid transparent; + font-weight: normal; + color: inherit; + + &:hover { + border-bottom: 2px solid var(--color-categories-item-border-selected); + } + } + + + label { + border-bottom: 2px solid var(--color-categories-item-border-selected); + background: var(--color-categories-item-selected); + color: var(--color-categories-item-selected-font); + } + + + label + section { + display: block; + } +} + +/* -- select -- */ +select { + height: 2.4rem; + margin-top: 0; + .ltr-margin-right(1rem); + margin-bottom: 0; + .ltr-margin-left(0); + padding: 0.2rem !important; + color: var(--color-search-font); + font-size: 0.9rem; + z-index: 100; + + &:hover, + &:focus { + cursor: pointer; + } +} + +@supports ((background-position-x: 100%) and ((appearance: none) or (-webkit-appearance: none) or (-moz-appearance: none))) { + select { + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + border-width: 0 2rem 0 0; + border-color: transparent; + background: data-uri('image/svg+xml;charset=UTF-8', @select-light-svg-path) no-repeat; + background-position-x: calc(100% + 2rem); + background-size: 2rem; + background-origin: content-box; + background-color: var(--color-toolkit-select-background); + outline: medium none; + text-overflow: ellipsis; + .rounded-corners-tiny; + + &:hover, + &:focus { + background-color: var(--color-toolkit-select-background-hover); + } + + option { + background-color: var(--color-base-background); + } + } + + @media (prefers-color-scheme: dark) { + html.theme-auto select, + html.theme-dark select { + background-image: data-uri('image/svg+xml;charset=UTF-8', @select-dark-svg-path); + } + } + + html.theme-dark select { + background-image: data-uri('image/svg+xml;charset=UTF-8', @select-dark-svg-path); + } +} + +/* -- checkbox-onoff -- */ +input.checkbox-onoff[type="checkbox"] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + cursor: pointer; + display: inline-block; + width: 2.5em; + height: 0.7em; + box-shadow: none !important; + margin: 0 16px; + border-radius: 10px; + position: relative; + + /* focus & hover */ + &:focus, + &:hover { + outline: none; + } + + &:focus::after { + content: ""; + position: absolute; + width: 3.5em; + height: 1.65em; + border: 1px solid var(--color-btn-background); + border-radius: 12px; + box-shadow: var(--color-btn-background) 0 0 3px; + z-index: 1200; + top: -0.55em; + left: -0.6em; + } + + &::before { + position: absolute; + top: -0.5em; + display: flex; + justify-content: center; + align-items: center; + font-size: 0.75em; + width: 1.875em; + height: 1.875em; + border-radius: 50%; + } +} + +/* check mark +reversed-checkbox displays unchecked checkedboxes as checked, and vice versa. +see https://github.com/searxng/searxng/blob/3408d061aab9abc6168fec9bbc6deab71b236dac/searx/templates/simple/preferences.html#L313 +*/ +input.checkbox-onoff[type="checkbox"], +input.checkbox-onoff.reversed-checkbox[type="checkbox"]:checked { + background: var(--color-toolkit-checkbox-onoff-off-background); + + &::before { + left: -0.5em; + content: "\2715"; + color: var(--color-toolkit-checkbox-onoff-off-mark-color); + background: var(--color-toolkit-checkbox-onoff-off-mark-background); + } +} + +input.checkbox-onoff[type="checkbox"]:checked, +input.checkbox-onoff.reversed-checkbox[type="checkbox"] { + background: var(--color-toolkit-checkbox-onoff-on-background); + + &::before { + left: calc(100% - 1.5em); + content: "\2713"; + color: var(--color-toolkit-checkbox-onoff-on-mark-color); + background: var(--color-toolkit-checkbox-onoff-on-mark-background); + } +} + +/* -- checkbox -- */ +@supports (transform: rotate(-45deg)) { + input[type=checkbox]:not(.checkbox-onoff) { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + + width: 20px; + height: 20px; + cursor: pointer; + position: relative; + top: 0; + left: 0; + border: 2px solid var(--color-toolkit-checkbox-input-border); + .rounded-corners(0.3em); + + &::after { + content: ''; + width: 9px; + height: 5px; + position: absolute; + top: 3px; + left: 2px; + border: 3px solid var(--color-toolkit-checkbox-label-border); + border-top: none; + border-right: none; + background: transparent; + opacity: 0; + transform: rotate(-45deg); + } + + &:checked::after { + border-color: var(--color-toolkit-checkbox-input-border); + opacity: 1; + } + } + + // disabled : can't be focused, show only the check mark + input[type=checkbox][disabled]:not(.checkbox-onoff) { + border: inherit; + background-color: transparent !important; + cursor: inherit; + } + + // if not checked and possible to checked then display a "light" check mark on hover + input.checkbox[type=checkbox]:not(:checked, [disabled], .checkbox-onoff):hover::after { + opacity: 0.5; + } +} + +@media screen and (max-width: @phone) { + .tabs > label { + width: 100%; + } +} + +/* -- loader -- */ +.loader, +.loader::after { + border-radius: 50%; + width: 2em; + height: 2em; +} + +.loader { + margin: 1em auto; + font-size: 10px; + position: relative; + text-indent: -9999em; + border-top: 0.5em solid var(--color-toolkit-loader-border); + border-right: 0.5em solid var(--color-toolkit-loader-border); + border-bottom: 0.5em solid var(--color-toolkit-loader-border); + border-left: 0.5em solid var(--color-toolkit-loader-borderleft); + -webkit-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); + -webkit-animation: load8 1.2s infinite linear; + animation: load8 1.2s infinite linear; +} + +@-webkit-keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +/* -- engine-tooltip -- */ +.engine-tooltip { + display: none; + position: absolute; + padding: 0.5rem 1rem; + margin: 0 0 0 2rem; + border: 1px solid var(--color-toolkit-engine-tooltip-border); + background: var(--color-toolkit-engine-tooltip-background); + font-size: 14px; + font-weight: normal; + z-index: 5000; + text-align: left; + .rounded-corners; +} + +th:hover .engine-tooltip, +td:hover .engine-tooltip, +.engine-tooltip:hover { + display: inline-block; +} + +/* -- stacked bar chart -- */ +.stacked-bar-chart { + margin: 0; + padding: 0 0.125rem 0 4rem; + width: 100%; + width: -moz-available; + width: -webkit-fill-available; + width: fill; + flex-flow: row nowrap; + align-items: center; + display: inline-flex; +} + +.stacked-bar-chart-value { + width: 3rem; + display: inline-block; + position: absolute; + padding: 0 0.5rem; + text-align: right; +} + +.stacked-bar-chart-base { + display: flex; + flex-shrink: 0; + flex-grow: 0; + flex-basis: unset; +} + +.stacked-bar-chart-median { + .stacked-bar-chart-base(); + + background: var(--color-base-font); + border: 1px solid rgba(var(--color-base-font-rgb), 0.9); + padding: 0.3rem 0; +} + +.stacked-bar-chart-rate80 { + .stacked-bar-chart-base(); + + background: transparent; + border: 1px solid rgba(var(--color-base-font-rgb), 0.3); + padding: 0.3rem 0; +} + +.stacked-bar-chart-rate95 { + .stacked-bar-chart-base(); + + background: transparent; + border-bottom: 1px dotted rgba(var(--color-base-font-rgb), 0.5); + padding: 0; +} + +.stacked-bar-chart-rate100 { + .stacked-bar-chart-base(); + + background: transparent; + border-left: 1px solid rgba(var(--color-base-font-rgb), 0.9); + padding: 0.4rem 0; + width: 1px; +} diff --git a/client/simple/src/less/toolkit_loader.less b/client/simple/src/less/toolkit_loader.less new file mode 100644 index 000000000..8b705e42b --- /dev/null +++ b/client/simple/src/less/toolkit_loader.less @@ -0,0 +1,29 @@ +.loader, +.loader::after { + border-radius: 50%; + width: 10em; + height: 10em; +} + +.loader { + margin: 60px auto; + font-size: 10px; + position: relative; + text-indent: -9999em; + border-top: 1.1em solid var(--color-loading-indicator); + border-right: 1.1em solid var(--color-loading-indicator); + border-bottom: 1.1em solid var(--color-loading-indicator); + border-left: 1.1em solid var(--color-loading-indicator-gap); + transform: translateZ(0); + animation: load8 1.1s infinite linear; +} + +@keyframes load8 { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} diff --git a/client/simple/src/svg/information-circle-outline.svg b/client/simple/src/svg/information-circle-outline.svg new file mode 100644 index 000000000..b7c300094 --- /dev/null +++ b/client/simple/src/svg/information-circle-outline.svg @@ -0,0 +1,6 @@ + + Information Circle + + + + \ No newline at end of file diff --git a/client/simple/src/svg/select-dark.svg b/client/simple/src/svg/select-dark.svg new file mode 100644 index 000000000..97335cea5 --- /dev/null +++ b/client/simple/src/svg/select-dark.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/client/simple/src/svg/select-light.svg b/client/simple/src/svg/select-light.svg new file mode 100644 index 000000000..3b707f018 --- /dev/null +++ b/client/simple/src/svg/select-light.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/searx/static/themes/simple/src/generated/pygments.less b/searx/static/themes/simple/src/generated/pygments.less deleted file mode 100644 index 971409116..000000000 --- a/searx/static/themes/simple/src/generated/pygments.less +++ /dev/null @@ -1,173 +0,0 @@ -/* - this file is generated automatically by searxng_extra/update/update_pygments.py - using pygments version 2.19.1 -*/ - - -.code-highlight { - - pre { line-height: 100%; } - td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } - span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } - td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } - span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } - .hll { background-color: #ffffcc } - .c { color: #3D7B7B; font-style: italic } /* Comment */ - .err { border: 1px solid #F00 } /* Error */ - .k { color: #008000; font-weight: bold } /* Keyword */ - .o { color: #666 } /* Operator */ - .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ - .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ - .cp { color: #9C6500 } /* Comment.Preproc */ - .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ - .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ - .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ - .gd { color: #A00000 } /* Generic.Deleted */ - .ge { font-style: italic } /* Generic.Emph */ - .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ - .gr { color: #E40000 } /* Generic.Error */ - .gh { color: #000080; font-weight: bold } /* Generic.Heading */ - .gi { color: #008400 } /* Generic.Inserted */ - .go { color: #717171 } /* Generic.Output */ - .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ - .gs { font-weight: bold } /* Generic.Strong */ - .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ - .gt { color: #04D } /* Generic.Traceback */ - .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ - .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ - .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ - .kp { color: #008000 } /* Keyword.Pseudo */ - .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ - .kt { color: #B00040 } /* Keyword.Type */ - .m { color: #666 } /* Literal.Number */ - .s { color: #BA2121 } /* Literal.String */ - .na { color: #687822 } /* Name.Attribute */ - .nb { color: #008000 } /* Name.Builtin */ - .nc { color: #00F; font-weight: bold } /* Name.Class */ - .no { color: #800 } /* Name.Constant */ - .nd { color: #A2F } /* Name.Decorator */ - .ni { color: #717171; font-weight: bold } /* Name.Entity */ - .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ - .nf { color: #00F } /* Name.Function */ - .nl { color: #767600 } /* Name.Label */ - .nn { color: #00F; font-weight: bold } /* Name.Namespace */ - .nt { color: #008000; font-weight: bold } /* Name.Tag */ - .nv { color: #19177C } /* Name.Variable */ - .ow { color: #A2F; font-weight: bold } /* Operator.Word */ - .w { color: #BBB } /* Text.Whitespace */ - .mb { color: #666 } /* Literal.Number.Bin */ - .mf { color: #666 } /* Literal.Number.Float */ - .mh { color: #666 } /* Literal.Number.Hex */ - .mi { color: #666 } /* Literal.Number.Integer */ - .mo { color: #666 } /* Literal.Number.Oct */ - .sa { color: #BA2121 } /* Literal.String.Affix */ - .sb { color: #BA2121 } /* Literal.String.Backtick */ - .sc { color: #BA2121 } /* Literal.String.Char */ - .dl { color: #BA2121 } /* Literal.String.Delimiter */ - .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ - .s2 { color: #BA2121 } /* Literal.String.Double */ - .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ - .sh { color: #BA2121 } /* Literal.String.Heredoc */ - .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ - .sx { color: #008000 } /* Literal.String.Other */ - .sr { color: #A45A77 } /* Literal.String.Regex */ - .s1 { color: #BA2121 } /* Literal.String.Single */ - .ss { color: #19177C } /* Literal.String.Symbol */ - .bp { color: #008000 } /* Name.Builtin.Pseudo */ - .fm { color: #00F } /* Name.Function.Magic */ - .vc { color: #19177C } /* Name.Variable.Class */ - .vg { color: #19177C } /* Name.Variable.Global */ - .vi { color: #19177C } /* Name.Variable.Instance */ - .vm { color: #19177C } /* Name.Variable.Magic */ - .il { color: #666 } /* Literal.Number.Integer.Long */ -} - -.code-highlight-dark(){ - .code-highlight { - - pre { line-height: 100%; } - td.linenos .normal { color: #3c4354; background-color: transparent; padding-left: 5px; padding-right: 5px; } - span.linenos { color: #3c4354; background-color: transparent; padding-left: 5px; padding-right: 5px; } - td.linenos .special { color: #3c4354; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } - span.linenos.special { color: #3c4354; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } - .hll { background-color: #6e7681 } - .c { color: #7E8AA1 } /* Comment */ - .err { color: #F88F7F } /* Error */ - .esc { color: #D4D2C8 } /* Escape */ - .g { color: #D4D2C8 } /* Generic */ - .k { color: #FFAD66 } /* Keyword */ - .l { color: #D5FF80 } /* Literal */ - .n { color: #D4D2C8 } /* Name */ - .o { color: #FFAD66 } /* Operator */ - .x { color: #D4D2C8 } /* Other */ - .p { color: #D4D2C8 } /* Punctuation */ - .ch { color: #F88F7F; font-style: italic } /* Comment.Hashbang */ - .cm { color: #7E8AA1 } /* Comment.Multiline */ - .cp { color: #FFAD66; font-weight: bold } /* Comment.Preproc */ - .cpf { color: #7E8AA1 } /* Comment.PreprocFile */ - .c1 { color: #7E8AA1 } /* Comment.Single */ - .cs { color: #7E8AA1; font-style: italic } /* Comment.Special */ - .gd { color: #F88F7F; background-color: #3D1E20 } /* Generic.Deleted */ - .ge { color: #D4D2C8; font-style: italic } /* Generic.Emph */ - .ges { color: #D4D2C8 } /* Generic.EmphStrong */ - .gr { color: #F88F7F } /* Generic.Error */ - .gh { color: #D4D2C8 } /* Generic.Heading */ - .gi { color: #6AD4AF; background-color: #19362C } /* Generic.Inserted */ - .go { color: #7E8AA1 } /* Generic.Output */ - .gp { color: #D4D2C8 } /* Generic.Prompt */ - .gs { color: #D4D2C8; font-weight: bold } /* Generic.Strong */ - .gu { color: #D4D2C8 } /* Generic.Subheading */ - .gt { color: #F88F7F } /* Generic.Traceback */ - .kc { color: #FFAD66 } /* Keyword.Constant */ - .kd { color: #FFAD66 } /* Keyword.Declaration */ - .kn { color: #FFAD66 } /* Keyword.Namespace */ - .kp { color: #FFAD66 } /* Keyword.Pseudo */ - .kr { color: #FFAD66 } /* Keyword.Reserved */ - .kt { color: #73D0FF } /* Keyword.Type */ - .ld { color: #D5FF80 } /* Literal.Date */ - .m { color: #DFBFFF } /* Literal.Number */ - .s { color: #D5FF80 } /* Literal.String */ - .na { color: #FFD173 } /* Name.Attribute */ - .nb { color: #FFD173 } /* Name.Builtin */ - .nc { color: #73D0FF } /* Name.Class */ - .no { color: #FFD173 } /* Name.Constant */ - .nd { color: #7E8AA1; font-weight: bold; font-style: italic } /* Name.Decorator */ - .ni { color: #95E6CB } /* Name.Entity */ - .ne { color: #73D0FF } /* Name.Exception */ - .nf { color: #FFD173 } /* Name.Function */ - .nl { color: #D4D2C8 } /* Name.Label */ - .nn { color: #D4D2C8 } /* Name.Namespace */ - .nx { color: #D4D2C8 } /* Name.Other */ - .py { color: #FFD173 } /* Name.Property */ - .nt { color: #5CCFE6 } /* Name.Tag */ - .nv { color: #D4D2C8 } /* Name.Variable */ - .ow { color: #FFAD66 } /* Operator.Word */ - .pm { color: #D4D2C8 } /* Punctuation.Marker */ - .w { color: #D4D2C8 } /* Text.Whitespace */ - .mb { color: #DFBFFF } /* Literal.Number.Bin */ - .mf { color: #DFBFFF } /* Literal.Number.Float */ - .mh { color: #DFBFFF } /* Literal.Number.Hex */ - .mi { color: #DFBFFF } /* Literal.Number.Integer */ - .mo { color: #DFBFFF } /* Literal.Number.Oct */ - .sa { color: #F29E74 } /* Literal.String.Affix */ - .sb { color: #D5FF80 } /* Literal.String.Backtick */ - .sc { color: #D5FF80 } /* Literal.String.Char */ - .dl { color: #D5FF80 } /* Literal.String.Delimiter */ - .sd { color: #7E8AA1 } /* Literal.String.Doc */ - .s2 { color: #D5FF80 } /* Literal.String.Double */ - .se { color: #95E6CB } /* Literal.String.Escape */ - .sh { color: #D5FF80 } /* Literal.String.Heredoc */ - .si { color: #95E6CB } /* Literal.String.Interpol */ - .sx { color: #95E6CB } /* Literal.String.Other */ - .sr { color: #95E6CB } /* Literal.String.Regex */ - .s1 { color: #D5FF80 } /* Literal.String.Single */ - .ss { color: #DFBFFF } /* Literal.String.Symbol */ - .bp { color: #5CCFE6 } /* Name.Builtin.Pseudo */ - .fm { color: #FFD173 } /* Name.Function.Magic */ - .vc { color: #D4D2C8 } /* Name.Variable.Class */ - .vg { color: #D4D2C8 } /* Name.Variable.Global */ - .vi { color: #D4D2C8 } /* Name.Variable.Instance */ - .vm { color: #D4D2C8 } /* Name.Variable.Magic */ - .il { color: #DFBFFF } /* Literal.Number.Integer.Long */ - } -} diff --git a/searx/static/themes/simple/src/js/head/00_init.js b/searx/static/themes/simple/src/js/head/00_init.js deleted file mode 100644 index a7c61c43e..000000000 --- a/searx/static/themes/simple/src/js/head/00_init.js +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: AGPL-3.0-or-later */ -(function (w, d) { - 'use strict'; - - // add data- properties - var script = d.currentScript || (function () { - var scripts = d.getElementsByTagName('script'); - return scripts[scripts.length - 1]; - })(); - - w.searxng = { - settings: JSON.parse(atob(script.getAttribute('client_settings'))) - }; - - // update the css - var htmlElement = d.getElementsByTagName("html")[0]; - htmlElement.classList.remove('no-js'); - htmlElement.classList.add('js'); - -})(window, document); diff --git a/searx/static/themes/simple/src/js/main/00_toolkit.js b/searx/static/themes/simple/src/js/main/00_toolkit.js deleted file mode 100644 index 4e374a019..000000000 --- a/searx/static/themes/simple/src/js/main/00_toolkit.js +++ /dev/null @@ -1,165 +0,0 @@ -/** - * @license - * (C) Copyright Contributors to the SearXNG project. - * (C) Copyright Contributors to the searx project (2014 - 2021). - * SPDX-License-Identifier: AGPL-3.0-or-later - */ -window.searxng = (function (w, d) { - - 'use strict'; - - // not invented here toolkit with bugs fixed elsewhere - // purposes : be just good enough and as small as possible - - // from https://plainjs.com/javascript/events/live-binding-event-handlers-14/ - if (w.Element) { - (function (ElementPrototype) { - ElementPrototype.matches = ElementPrototype.matches || - ElementPrototype.matchesSelector || - ElementPrototype.webkitMatchesSelector || - ElementPrototype.msMatchesSelector || - function (selector) { - var node = this, nodes = (node.parentNode || node.document).querySelectorAll(selector), i = -1; - while (nodes[++i] && nodes[i] != node); - return !!nodes[i]; - }; - })(Element.prototype); - } - - function callbackSafe (callback, el, e) { - try { - callback.call(el, e); - } catch (exception) { - console.log(exception); - } - } - - var searxng = window.searxng || {}; - - searxng.on = function (obj, eventType, callback, useCapture) { - useCapture = useCapture || false; - if (typeof obj !== 'string') { - // obj HTMLElement, HTMLDocument - obj.addEventListener(eventType, callback, useCapture); - } else { - // obj is a selector - d.addEventListener(eventType, function (e) { - var el = e.target || e.srcElement, found = false; - while (el && el.matches && el !== d && !(found = el.matches(obj))) el = el.parentElement; - if (found) callbackSafe(callback, el, e); - }, useCapture); - } - }; - - searxng.ready = function (callback) { - if (document.readyState != 'loading') { - callback.call(w); - } else { - w.addEventListener('DOMContentLoaded', callback.bind(w)); - } - }; - - searxng.http = function (method, url, data = null) { - return new Promise(function (resolve, reject) { - try { - var req = new XMLHttpRequest(); - req.open(method, url, true); - req.timeout = 20000; - - // On load - req.onload = function () { - if (req.status == 200) { - resolve(req.response, req.responseType); - } else { - reject(Error(req.statusText)); - } - }; - - // Handle network errors - req.onerror = function () { - reject(Error("Network Error")); - }; - - req.onabort = function () { - reject(Error("Transaction is aborted")); - }; - - req.ontimeout = function () { - reject(Error("Timeout")); - } - - // Make the request - if (data) { - req.send(data) - } else { - req.send(); - } - } catch (ex) { - reject(ex); - } - }); - }; - - searxng.loadStyle = function (src) { - var path = searxng.settings.theme_static_path + "/" + src, - id = "style_" + src.replace('.', '_'), - s = d.getElementById(id); - if (s === null) { - s = d.createElement('link'); - s.setAttribute('id', id); - s.setAttribute('rel', 'stylesheet'); - s.setAttribute('type', 'text/css'); - s.setAttribute('href', path); - d.body.appendChild(s); - } - }; - - searxng.loadScript = function (src, callback) { - var path = searxng.settings.theme_static_path + "/" + src, - id = "script_" + src.replace('.', '_'), - s = d.getElementById(id); - if (s === null) { - s = d.createElement('script'); - s.setAttribute('id', id); - s.setAttribute('src', path); - s.onload = callback; - s.onerror = function () { - s.setAttribute('error', '1'); - }; - d.body.appendChild(s); - } else if (!s.hasAttribute('error')) { - try { - callback.apply(s, []); - } catch (exception) { - console.log(exception); - } - } else { - console.log("callback not executed : script '" + path + "' not loaded."); - } - }; - - searxng.insertBefore = function (newNode, referenceNode) { - referenceNode.parentNode.insertBefore(newNode, referenceNode); - }; - - searxng.insertAfter = function (newNode, referenceNode) { - referenceNode.parentNode.insertAfter(newNode, referenceNode.nextSibling); - }; - - searxng.on('.close', 'click', function () { - this.parentNode.classList.add('invisible'); - }); - - function getEndpoint () { - for (var className of d.getElementsByTagName('body')[0].classList.values()) { - if (className.endsWith('_endpoint')) { - return className.split('_')[0]; - } - } - return ''; - } - - searxng.endpoint = getEndpoint(); - - return searxng; -})(window, document); diff --git a/searx/static/themes/simple/src/js/main/infinite_scroll.js b/searx/static/themes/simple/src/js/main/infinite_scroll.js deleted file mode 100644 index 07db3305a..000000000 --- a/searx/static/themes/simple/src/js/main/infinite_scroll.js +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -/* global searxng */ - -searxng.ready(function () { - 'use strict'; - - searxng.infinite_scroll_supported = ( - 'IntersectionObserver' in window && - 'IntersectionObserverEntry' in window && - 'intersectionRatio' in window.IntersectionObserverEntry.prototype); - - if (searxng.endpoint !== 'results') { - return; - } - - if (!searxng.infinite_scroll_supported) { - console.log('IntersectionObserver not supported'); - return; - } - - let d = document; - var onlyImages = d.getElementById('results').classList.contains('only_template_images'); - - function newLoadSpinner () { - var loader = d.createElement('div'); - loader.classList.add('loader'); - return loader; - } - - function replaceChildrenWith (element, children) { - element.textContent = ''; - children.forEach(child => element.appendChild(child)); - } - - function loadNextPage (callback) { - var form = d.querySelector('#pagination form.next_page'); - if (!form) { - return - } - replaceChildrenWith(d.querySelector('#pagination'), [ newLoadSpinner() ]); - var formData = new FormData(form); - searxng.http('POST', d.querySelector('#search').getAttribute('action'), formData).then( - function (response) { - var nextPageDoc = new DOMParser().parseFromString(response, 'text/html'); - var articleList = nextPageDoc.querySelectorAll('#urls article'); - var paginationElement = nextPageDoc.querySelector('#pagination'); - d.querySelector('#pagination').remove(); - if (articleList.length > 0 && !onlyImages) { - // do not add
element when there are only images - d.querySelector('#urls').appendChild(d.createElement('hr')); - } - articleList.forEach(articleElement => { - d.querySelector('#urls').appendChild(articleElement); - }); - if (paginationElement) { - d.querySelector('#results').appendChild(paginationElement); - callback(); - } - } - ).catch( - function (err) { - console.log(err); - var e = d.createElement('div'); - e.textContent = searxng.settings.translations.error_loading_next_page; - e.classList.add('dialog-error'); - e.setAttribute('role', 'alert'); - replaceChildrenWith(d.querySelector('#pagination'), [ e ]); - } - ) - } - - if (searxng.settings.infinite_scroll && searxng.infinite_scroll_supported) { - const intersectionObserveOptions = { - rootMargin: "20rem", - }; - const observedSelector = 'article.result:last-child'; - const observer = new IntersectionObserver(entries => { - const paginationEntry = entries[0]; - if (paginationEntry.isIntersecting) { - observer.unobserve(paginationEntry.target); - loadNextPage(() => observer.observe(d.querySelector(observedSelector), intersectionObserveOptions)); - } - }); - observer.observe(d.querySelector(observedSelector), intersectionObserveOptions); - } - -}); diff --git a/searx/static/themes/simple/src/js/main/keyboard.js b/searx/static/themes/simple/src/js/main/keyboard.js deleted file mode 100644 index e16134579..000000000 --- a/searx/static/themes/simple/src/js/main/keyboard.js +++ /dev/null @@ -1,461 +0,0 @@ -/* SPDX-License-Identifier: AGPL-3.0-or-later */ -/* global searxng */ - -searxng.ready(function () { - - function isElementInDetail (el) { - while (el !== undefined) { - if (el.classList.contains('detail')) { - return true; - } - if (el.classList.contains('result')) { - // we found a result, no need to go to the root of the document: - // el is not inside a
element - return false; - } - el = el.parentNode; - } - return false; - } - - function getResultElement (el) { - while (el !== undefined) { - if (el.classList.contains('result')) { - return el; - } - el = el.parentNode; - } - return undefined; - } - - function isImageResult (resultElement) { - return resultElement && resultElement.classList.contains('result-images'); - } - - searxng.on('.result', 'click', function (e) { - if (!isElementInDetail(e.target)) { - highlightResult(this)(true, true); - let resultElement = getResultElement(e.target); - if (isImageResult(resultElement)) { - e.preventDefault(); - searxng.selectImage(resultElement); - } - } - }); - - searxng.on('.result a', 'focus', function (e) { - if (!isElementInDetail(e.target)) { - let resultElement = getResultElement(e.target); - if (resultElement && resultElement.getAttribute("data-vim-selected") === null) { - highlightResult(resultElement)(true); - } - if (isImageResult(resultElement)) { - searxng.selectImage(resultElement); - } - } - }, true); - - /* common base for layouts */ - var baseKeyBinding = { - 'Escape': { - key: 'ESC', - fun: removeFocus, - des: 'remove focus from the focused input', - cat: 'Control' - }, - 'c': { - key: 'c', - fun: copyURLToClipboard, - des: 'copy url of the selected result to the clipboard', - cat: 'Results' - }, - 'h': { - key: 'h', - fun: toggleHelp, - des: 'toggle help window', - cat: 'Other' - }, - 'i': { - key: 'i', - fun: searchInputFocus, - des: 'focus on the search input', - cat: 'Control' - }, - 'n': { - key: 'n', - fun: GoToNextPage(), - des: 'go to next page', - cat: 'Results' - }, - 'o': { - key: 'o', - fun: openResult(false), - des: 'open search result', - cat: 'Results' - }, - 'p': { - key: 'p', - fun: GoToPreviousPage(), - des: 'go to previous page', - cat: 'Results' - }, - 'r': { - key: 'r', - fun: reloadPage, - des: 'reload page from the server', - cat: 'Control' - }, - 't': { - key: 't', - fun: openResult(true), - des: 'open the result in a new tab', - cat: 'Results' - }, - }; - var keyBindingLayouts = { - - "default": Object.assign( - { /* SearXNG layout */ - 'ArrowLeft': { - key: '←', - fun: highlightResult('up'), - des: 'select previous search result', - cat: 'Results' - }, - 'ArrowRight': { - key: '→', - fun: highlightResult('down'), - des: 'select next search result', - cat: 'Results' - }, - }, baseKeyBinding), - - 'vim': Object.assign( - { /* Vim-like Key Layout. */ - 'b': { - key: 'b', - fun: scrollPage(-window.innerHeight), - des: 'scroll one page up', - cat: 'Navigation' - }, - 'f': { - key: 'f', - fun: scrollPage(window.innerHeight), - des: 'scroll one page down', - cat: 'Navigation' - }, - 'u': { - key: 'u', - fun: scrollPage(-window.innerHeight / 2), - des: 'scroll half a page up', - cat: 'Navigation' - }, - 'd': { - key: 'd', - fun: scrollPage(window.innerHeight / 2), - des: 'scroll half a page down', - cat: 'Navigation' - }, - 'g': { - key: 'g', - fun: scrollPageTo(-document.body.scrollHeight, 'top'), - des: 'scroll to the top of the page', - cat: 'Navigation' - }, - 'v': { - key: 'v', - fun: scrollPageTo(document.body.scrollHeight, 'bottom'), - des: 'scroll to the bottom of the page', - cat: 'Navigation' - }, - 'k': { - key: 'k', - fun: highlightResult('up'), - des: 'select previous search result', - cat: 'Results' - }, - 'j': { - key: 'j', - fun: highlightResult('down'), - des: 'select next search result', - cat: 'Results' - }, - 'y': { - key: 'y', - fun: copyURLToClipboard, - des: 'copy url of the selected result to the clipboard', - cat: 'Results' - }, - }, baseKeyBinding) - } - - var keyBindings = keyBindingLayouts[searxng.settings.hotkeys] || keyBindingLayouts.default; - - searxng.on(document, "keydown", function (e) { - // check for modifiers so we don't break browser's hotkeys - if ( - Object.prototype.hasOwnProperty.call(keyBindings, e.key) - && !e.ctrlKey && !e.altKey - && !e.shiftKey && !e.metaKey - ) { - var tagName = e.target.tagName.toLowerCase(); - if (e.key === 'Escape') { - keyBindings[e.key].fun(e); - } else { - if (e.target === document.body || tagName === 'a' || tagName === 'button') { - e.preventDefault(); - keyBindings[e.key].fun(); - } - } - } - }); - - function highlightResult (which) { - return function (noScroll, keepFocus) { - var current = document.querySelector('.result[data-vim-selected]'), - effectiveWhich = which; - if (current === null) { - // no selection : choose the first one - current = document.querySelector('.result'); - if (current === null) { - // no first one : there are no results - return; - } - // replace up/down actions by selecting first one - if (which === "down" || which === "up") { - effectiveWhich = current; - } - } - - var next, results = document.querySelectorAll('.result'); - results = Array.from(results); // convert NodeList to Array for further use - - if (typeof effectiveWhich !== 'string') { - next = effectiveWhich; - } else { - switch (effectiveWhich) { - case 'visible': - var top = document.documentElement.scrollTop || document.body.scrollTop; - var bot = top + document.documentElement.clientHeight; - - for (var i = 0; i < results.length; i++) { - next = results[i]; - var etop = next.offsetTop; - var ebot = etop + next.clientHeight; - - if ((ebot <= bot) && (etop > top)) { - break; - } - } - break; - case 'down': - next = results[results.indexOf(current) + 1] || current; - break; - case 'up': - next = results[results.indexOf(current) - 1] || current; - break; - case 'bottom': - next = results[results.length - 1]; - break; - case 'top': - /* falls through */ - default: - next = results[0]; - } - } - - if (next) { - current.removeAttribute('data-vim-selected'); - next.setAttribute('data-vim-selected', 'true'); - if (!keepFocus) { - var link = next.querySelector('h3 a') || next.querySelector('a'); - if (link !== null) { - link.focus(); - } - } - if (!noScroll) { - scrollPageToSelected(); - } - } - }; - } - - function reloadPage () { - document.location.reload(true); - } - - function removeFocus (e) { - const tagName = e.target.tagName.toLowerCase(); - if (document.activeElement && (tagName === 'input' || tagName === 'select' || tagName === 'textarea')) { - document.activeElement.blur(); - } else { - searxng.closeDetail(); - } - } - - function pageButtonClick (css_selector) { - return function () { - var button = document.querySelector(css_selector); - if (button) { - button.click(); - } - }; - } - - function GoToNextPage () { - return pageButtonClick('nav#pagination .next_page button[type="submit"]'); - } - - function GoToPreviousPage () { - return pageButtonClick('nav#pagination .previous_page button[type="submit"]'); - } - - function scrollPageToSelected () { - var sel = document.querySelector('.result[data-vim-selected]'); - if (sel === null) { - return; - } - var wtop = document.documentElement.scrollTop || document.body.scrollTop, - wheight = document.documentElement.clientHeight, - etop = sel.offsetTop, - ebot = etop + sel.clientHeight, - offset = 120; - // first element ? - if ((sel.previousElementSibling === null) && (ebot < wheight)) { - // set to the top of page if the first element - // is fully included in the viewport - window.scroll(window.scrollX, 0); - return; - } - if (wtop > (etop - offset)) { - window.scroll(window.scrollX, etop - offset); - } else { - var wbot = wtop + wheight; - if (wbot < (ebot + offset)) { - window.scroll(window.scrollX, ebot - wheight + offset); - } - } - } - - function scrollPage (amount) { - return function () { - window.scrollBy(0, amount); - highlightResult('visible')(); - }; - } - - function scrollPageTo (position, nav) { - return function () { - window.scrollTo(0, position); - highlightResult(nav)(); - }; - } - - function searchInputFocus () { - window.scrollTo(0, 0); - var q = document.querySelector('#q'); - q.focus(); - if (q.setSelectionRange) { - var len = q.value.length; - q.setSelectionRange(len, len); - } - } - - function openResult (newTab) { - return function () { - var link = document.querySelector('.result[data-vim-selected] h3 a'); - if (link === null) { - link = document.querySelector('.result[data-vim-selected] > a'); - } - if (link !== null) { - var url = link.getAttribute('href'); - if (newTab) { - window.open(url); - } else { - window.location.href = url; - } - } - }; - } - - function initHelpContent (divElement) { - var categories = {}; - - for (var k in keyBindings) { - var key = keyBindings[k]; - categories[key.cat] = categories[key.cat] || []; - categories[key.cat].push(key); - } - - var sorted = Object.keys(categories).sort(function (a, b) { - return categories[b].length - categories[a].length; - }); - - if (sorted.length === 0) { - return; - } - - var html = '×'; - html += '

How to navigate SearXNG with hotkeys

'; - html += ''; - - for (var i = 0; i < sorted.length; i++) { - var cat = categories[sorted[i]]; - - var lastCategory = i === (sorted.length - 1); - var first = i % 2 === 0; - - if (first) { - html += ''; - } - html += ''; // col-sm-* - - if (!first || lastCategory) { - html += ''; // row - } - } - - html += '
'; - - html += '

' + cat[0].cat + '

'; - html += '
    '; - - for (var cj in cat) { - html += '
  • ' + cat[cj].key + ' ' + cat[cj].des + '
  • '; - } - - html += '
'; - html += '
'; - - divElement.innerHTML = html; - } - - function toggleHelp () { - var helpPanel = document.querySelector('#vim-hotkeys-help'); - if (helpPanel === undefined || helpPanel === null) { - // first call - helpPanel = document.createElement('div'); - helpPanel.id = 'vim-hotkeys-help'; - helpPanel.className = 'dialog-modal'; - initHelpContent(helpPanel); - var body = document.getElementsByTagName('body')[0]; - body.appendChild(helpPanel); - } else { - // toggle hidden - helpPanel.classList.toggle('invisible'); - return; - } - } - - function copyURLToClipboard () { - var currentUrlElement = document.querySelector('.result[data-vim-selected] h3 a'); - if (currentUrlElement === null) return; - - const url = currentUrlElement.getAttribute('href'); - navigator.clipboard.writeText(url); - } - - searxng.scrollPageToSelected = scrollPageToSelected; - searxng.selectNext = highlightResult('down'); - searxng.selectPrevious = highlightResult('up'); -}); diff --git a/searx/static/themes/simple/src/js/main/mapresult.js b/searx/static/themes/simple/src/js/main/mapresult.js deleted file mode 100644 index 2c3777678..000000000 --- a/searx/static/themes/simple/src/js/main/mapresult.js +++ /dev/null @@ -1,74 +0,0 @@ -/* SPDX-License-Identifier: AGPL-3.0-or-later */ -/* global L */ -(function (w, d, searxng) { - 'use strict'; - - searxng.ready(function () { - searxng.on('.searxng_init_map', 'click', function (event) { - // no more request - this.classList.remove("searxng_init_map"); - - // - var leaflet_target = this.dataset.leafletTarget; - var map_lon = parseFloat(this.dataset.mapLon); - var map_lat = parseFloat(this.dataset.mapLat); - var map_zoom = parseFloat(this.dataset.mapZoom); - var map_boundingbox = JSON.parse(this.dataset.mapBoundingbox); - var map_geojson = JSON.parse(this.dataset.mapGeojson); - - searxng.loadStyle('css/leaflet.css'); - searxng.loadScript('js/leaflet.js', function () { - var map_bounds = null; - if (map_boundingbox) { - var southWest = L.latLng(map_boundingbox[0], map_boundingbox[2]); - var northEast = L.latLng(map_boundingbox[1], map_boundingbox[3]); - map_bounds = L.latLngBounds(southWest, northEast); - } - - // init map - var map = L.map(leaflet_target); - // create the tile layer with correct attribution - var osmMapnikUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; - var osmMapnikAttrib = 'Map data © OpenStreetMap contributors'; - var osmMapnik = new L.TileLayer(osmMapnikUrl, {minZoom: 1, maxZoom: 19, attribution: osmMapnikAttrib}); - var osmWikimediaUrl = 'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png'; - var osmWikimediaAttrib = 'Wikimedia maps | Maps data © OpenStreetMap contributors'; - var osmWikimedia = new L.TileLayer(osmWikimediaUrl, {minZoom: 1, maxZoom: 19, attribution: osmWikimediaAttrib}); - // init map view - if (map_bounds) { - // TODO hack: https://github.com/Leaflet/Leaflet/issues/2021 - // Still useful ? - setTimeout(function () { - map.fitBounds(map_bounds, { - maxZoom: 17 - }); - }, 0); - } else if (map_lon && map_lat) { - if (map_zoom) { - map.setView(new L.latLng(map_lat, map_lon), map_zoom); - } else { - map.setView(new L.latLng(map_lat, map_lon), 8); - } - } - - map.addLayer(osmMapnik); - - var baseLayers = { - "OSM Mapnik": osmMapnik, - "OSM Wikimedia": osmWikimedia, - }; - - L.control.layers(baseLayers).addTo(map); - - if (map_geojson) { - L.geoJson(map_geojson).addTo(map); - } /* else if(map_bounds) { - L.rectangle(map_bounds, {color: "#ff7800", weight: 3, fill:false}).addTo(map); - } */ - }); - - // this event occur only once per element - event.preventDefault(); - }); - }); -})(window, document, window.searxng); diff --git a/searx/static/themes/simple/src/js/main/preferences.js b/searx/static/themes/simple/src/js/main/preferences.js deleted file mode 100644 index a0b853d61..000000000 --- a/searx/static/themes/simple/src/js/main/preferences.js +++ /dev/null @@ -1,53 +0,0 @@ -/* SPDX-License-Identifier: AGPL-3.0-or-later */ -(function (w, d, searxng) { - 'use strict'; - - if (searxng.endpoint !== 'preferences') { - return; - } - - searxng.ready(function () { - let engine_descriptions = null; - function load_engine_descriptions () { - if (engine_descriptions == null) { - searxng.http("GET", "engine_descriptions.json").then(function (content) { - engine_descriptions = JSON.parse(content); - for (const [engine_name, description] of Object.entries(engine_descriptions)) { - let elements = d.querySelectorAll('[data-engine-name="' + engine_name + '"] .engine-description'); - for (const element of elements) { - let source = ' (' + searxng.settings.translations.Source + ': ' + description[1] + ')'; - element.innerHTML = description[0] + source; - } - } - }); - } - } - - for (const el of d.querySelectorAll('[data-engine-name]')) { - searxng.on(el, 'mouseenter', load_engine_descriptions); - } - - const enableAllEngines = d.querySelectorAll(".enable-all-engines"); - const disableAllEngines = d.querySelectorAll(".disable-all-engines"); - const engineToggles = d.querySelectorAll('tbody input[type=checkbox][class~=checkbox-onoff]'); - const toggleEngines = (enable) => { - for (const el of engineToggles) { - // check if element visible, so that only engines of the current category are modified - if (el.offsetParent !== null) el.checked = !enable; - } - }; - for (const el of enableAllEngines) { - searxng.on(el, 'click', () => toggleEngines(true)); - } - for (const el of disableAllEngines) { - searxng.on(el, 'click', () => toggleEngines(false)); - } - - const copyHashButton = d.querySelector("#copy-hash"); - searxng.on(copyHashButton, 'click', (e) => { - e.preventDefault(); - navigator.clipboard.writeText(copyHashButton.dataset.hash); - copyHashButton.innerText = copyHashButton.dataset.copiedText; - }); - }); -})(window, document, window.searxng); diff --git a/searx/static/themes/simple/src/js/main/results.js b/searx/static/themes/simple/src/js/main/results.js deleted file mode 100644 index cc7c7efcd..000000000 --- a/searx/static/themes/simple/src/js/main/results.js +++ /dev/null @@ -1,181 +0,0 @@ -/* SPDX-License-Identifier: AGPL-3.0-or-later */ -(function (w, d, searxng) { - 'use strict'; - - if (searxng.endpoint !== 'results') { - return; - } - - searxng.ready(function () { - d.querySelectorAll('#urls img').forEach( - img => - img.addEventListener( - 'error', () => { - // console.log("ERROR can't load: " + img.src); - img.src = window.searxng.settings.theme_static_path + "/img/img_load_error.svg"; - }, - {once: true} - )); - - if (d.querySelector('#search_url button#copy_url')) { - d.querySelector('#search_url button#copy_url').style.display = "block"; - } - - searxng.on('.btn-collapse', 'click', function () { - var btnLabelCollapsed = this.getAttribute('data-btn-text-collapsed'); - var btnLabelNotCollapsed = this.getAttribute('data-btn-text-not-collapsed'); - var target = this.getAttribute('data-target'); - var targetElement = d.querySelector(target); - var html = this.innerHTML; - if (this.classList.contains('collapsed')) { - html = html.replace(btnLabelCollapsed, btnLabelNotCollapsed); - } else { - html = html.replace(btnLabelNotCollapsed, btnLabelCollapsed); - } - this.innerHTML = html; - this.classList.toggle('collapsed'); - targetElement.classList.toggle('invisible'); - }); - - searxng.on('.media-loader', 'click', function () { - var target = this.getAttribute('data-target'); - var iframe_load = d.querySelector(target + ' > iframe'); - var srctest = iframe_load.getAttribute('src'); - if (srctest === null || srctest === undefined || srctest === false) { - iframe_load.setAttribute('src', iframe_load.getAttribute('data-src')); - } - }); - - searxng.on('#copy_url', 'click', function () { - var target = this.parentElement.querySelector('pre'); - navigator.clipboard.writeText(target.innerText); - this.innerText = this.dataset.copiedText; - }); - - // searxng.selectImage (gallery) - // ----------------------------- - - // setTimeout() ID, needed to cancel *last* loadImage - let imgTimeoutID; - - // progress spinner, while an image is loading - const imgLoaderSpinner = d.createElement('div'); - imgLoaderSpinner.classList.add('loader'); - - // singleton image object, which is used for all loading processes of a - // detailed image - const imgLoader = new Image(); - - const loadImage = (imgSrc, onSuccess) => { - // if defered image load exists, stop defered task. - if (imgTimeoutID) clearTimeout(imgTimeoutID); - - // defer load of the detail image for 1 sec - imgTimeoutID = setTimeout(() => { - imgLoader.src = imgSrc; - }, 1000); - - // set handlers in the on-properties - imgLoader.onload = () => { - onSuccess(); - imgLoaderSpinner.remove(); - }; - imgLoader.onerror = () => { - imgLoaderSpinner.remove(); - }; - }; - - searxng.selectImage = (resultElement) => { - - // add a class that can be evaluated in the CSS and indicates that the - // detail view is open - d.getElementById('results').classList.add('image-detail-open'); - - // add a hash to the browser history so that pressing back doesn't return - // to the previous page this allows us to dismiss the image details on - // pressing the back button on mobile devices - window.location.hash = '#image-viewer'; - - searxng.scrollPageToSelected(); - - // if there is none element given by the caller, stop here - if (!resultElement) return; - - // find object in the element, if there is none, stop here. - const img = resultElement.querySelector('.result-images-source img'); - if (!img) return; - - // - const src = img.getAttribute('data-src'); - - // already loaded high-res image or no high-res image available - if (!src) return; - - // use the image thumbnail until the image is fully loaded - const thumbnail = resultElement.querySelector('.image_thumbnail'); - img.src = thumbnail.src; - - // show a progress spinner - const detailElement = resultElement.querySelector('.detail'); - detailElement.appendChild(imgLoaderSpinner); - - // load full size image in background - loadImage(src, () => { - // after the singelton loadImage has loaded the detail image into the - // cache, it can be used in the origin as src property. - img.src = src; - img.removeAttribute('data-src'); - }); - }; - - searxng.closeDetail = function () { - d.getElementById('results').classList.remove('image-detail-open'); - // remove #image-viewer hash from url by navigating back - if (window.location.hash == '#image-viewer') window.history.back(); - searxng.scrollPageToSelected(); - }; - searxng.on('.result-detail-close', 'click', e => { - e.preventDefault(); - searxng.closeDetail(); - }); - searxng.on('.result-detail-previous', 'click', e => { - e.preventDefault(); - searxng.selectPrevious(false); - }); - searxng.on('.result-detail-next', 'click', e => { - e.preventDefault(); - searxng.selectNext(false); - }); - - // listen for the back button to be pressed and dismiss the image details when called - window.addEventListener('hashchange', () => { - if (window.location.hash != '#image-viewer') searxng.closeDetail(); - }); - - d.querySelectorAll('.swipe-horizontal').forEach( - obj => { - obj.addEventListener('swiped-left', function () { - searxng.selectNext(false); - }); - obj.addEventListener('swiped-right', function () { - searxng.selectPrevious(false); - }); - } - ); - - w.addEventListener('scroll', function () { - var e = d.getElementById('backToTop'), - scrollTop = document.documentElement.scrollTop || document.body.scrollTop, - results = d.getElementById('results'); - if (e !== null) { - if (scrollTop >= 100) { - results.classList.add('scrolling'); - } else { - results.classList.remove('scrolling'); - } - } - }, true); - - }); - -})(window, document, window.searxng); diff --git a/searx/static/themes/simple/src/js/main/search.js b/searx/static/themes/simple/src/js/main/search.js deleted file mode 100644 index 1a53713c0..000000000 --- a/searx/static/themes/simple/src/js/main/search.js +++ /dev/null @@ -1,207 +0,0 @@ -/* SPDX-License-Identifier: AGPL-3.0-or-later */ -/* global AutoComplete */ -(function (w, d, searxng) { - 'use strict'; - - var qinput_id = "q", qinput; - - const isMobile = window.matchMedia("only screen and (max-width: 50em)").matches; - - function submitIfQuery () { - if (qinput.value.length > 0) { - var search = document.getElementById('search'); - setTimeout(search.submit.bind(search), 0); - } - } - - function createClearButton (qinput) { - var cs = document.getElementById('clear_search'); - var updateClearButton = function () { - if (qinput.value.length === 0) { - cs.classList.add("empty"); - } else { - cs.classList.remove("empty"); - } - }; - - // update status, event listener - updateClearButton(); - cs.addEventListener('click', function (ev) { - qinput.value = ''; - qinput.focus(); - updateClearButton(); - ev.preventDefault(); - }); - qinput.addEventListener('input', updateClearButton, false); - } - - searxng.ready(function () { - qinput = d.getElementById(qinput_id); - - if (qinput !== null) { - // clear button - createClearButton(qinput); - - // autocompleter - if (searxng.settings.autocomplete) { - searxng.autocomplete = AutoComplete.call(w, { - Url: "./autocompleter", - EmptyMessage: searxng.settings.translations.no_item_found, - HttpMethod: searxng.settings.method, - HttpHeaders: { - "Content-type": "application/x-www-form-urlencoded", - "X-Requested-With": "XMLHttpRequest" - }, - MinChars: searxng.settings.autocomplete_min, - Delay: 300, - _Position: function () {}, - _Open: function () { - var params = this; - Array.prototype.forEach.call(this.DOMResults.getElementsByTagName("li"), function (li) { - if (li.getAttribute("class") != "locked") { - li.onmousedown = function () { - params._Select(li); - }; - } - }); - }, - _Select: function (item) { - AutoComplete.defaults._Select.call(this, item); - var form = item.closest('form'); - if (form) { - form.submit(); - } - }, - _MinChars: function () { - if (this.Input.value.indexOf('!') > -1) { - return 0; - } else { - return AutoComplete.defaults._MinChars.call(this); - } - }, - KeyboardMappings: Object.assign({}, AutoComplete.defaults.KeyboardMappings, { - "KeyUpAndDown_up": Object.assign({}, AutoComplete.defaults.KeyboardMappings.KeyUpAndDown_up, { - Callback: function (event) { - AutoComplete.defaults.KeyboardMappings.KeyUpAndDown_up.Callback.call(this, event); - var liActive = this.DOMResults.querySelector("li.active"); - if (liActive) { - AutoComplete.defaults._Select.call(this, liActive); - } - }, - }), - "Tab": Object.assign({}, AutoComplete.defaults.KeyboardMappings.Enter, { - Conditions: [{ - Is: 9, - Not: false - }], - Callback: function (event) { - if (this.DOMResults.getAttribute("class").indexOf("open") != -1) { - var liActive = this.DOMResults.querySelector("li.active"); - if (liActive !== null) { - AutoComplete.defaults._Select.call(this, liActive); - event.preventDefault(); - } - } - }, - }) - }), - }, "#" + qinput_id); - } - - /* - Monkey patch autocomplete.js to fix a bug - With the POST method, the values are not URL encoded: query like "1 + 1" are sent as "1 1" since space are URL encoded as plus. - See HTML specifications: - * HTML5: https://url.spec.whatwg.org/#concept-urlencoded-serializer - * HTML4: https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1 - - autocomplete.js does not URL encode the name and values: - https://github.com/autocompletejs/autocomplete.js/blob/87069524f3b95e68f1b54d8976868e0eac1b2c83/src/autocomplete.ts#L665 - - The monkey patch overrides the compiled version of the ajax function. - See https://github.com/autocompletejs/autocomplete.js/blob/87069524f3b95e68f1b54d8976868e0eac1b2c83/dist/autocomplete.js#L143-L158 - The patch changes only the line 156 from - params.Request.send(params._QueryArg() + "=" + params._Pre()); - to - params.Request.send(encodeURIComponent(params._QueryArg()) + "=" + encodeURIComponent(params._Pre())); - - Related to: - * https://github.com/autocompletejs/autocomplete.js/issues/78 - * https://github.com/searxng/searxng/issues/1695 - */ - AutoComplete.prototype.ajax = function (params, request, timeout) { - if (timeout === void 0) { timeout = true; } - if (params.$AjaxTimer) { - window.clearTimeout(params.$AjaxTimer); - } - if (timeout === true) { - params.$AjaxTimer = window.setTimeout(AutoComplete.prototype.ajax.bind(null, params, request, false), params.Delay); - } else { - if (params.Request) { - params.Request.abort(); - } - params.Request = request; - params.Request.send(encodeURIComponent(params._QueryArg()) + "=" + encodeURIComponent(params._Pre())); - } - }; - - if (!isMobile && document.querySelector('.index_endpoint')) { - qinput.focus(); - } - } - - // Additionally to searching when selecting a new category, we also - // automatically start a new search request when the user changes a search - // filter (safesearch, time range or language) (this requires JavaScript - // though) - if ( - qinput !== null - && searxng.settings.search_on_category_select - // If .search_filters is undefined (invisible) we are on the homepage and - // hence don't have to set any listeners - && d.querySelector(".search_filters") != null - ) { - searxng.on(d.getElementById('safesearch'), 'change', submitIfQuery); - searxng.on(d.getElementById('time_range'), 'change', submitIfQuery); - searxng.on(d.getElementById('language'), 'change', submitIfQuery); - } - - const categoryButtons = d.querySelectorAll("button.category_button"); - for (let button of categoryButtons) { - searxng.on(button, 'click', (event) => { - if (event.shiftKey) { - event.preventDefault(); - button.classList.toggle("selected"); - return; - } - - // manually deselect the old selection when a new category is selected - const selectedCategories = d.querySelectorAll("button.category_button.selected"); - for (let categoryButton of selectedCategories) { - categoryButton.classList.remove("selected"); - } - button.classList.add("selected"); - }) - } - - // override form submit action to update the actually selected categories - const form = d.querySelector("#search"); - if (form != null) { - searxng.on(form, 'submit', (event) => { - event.preventDefault(); - const categoryValuesInput = d.querySelector("#selected-categories"); - if (categoryValuesInput) { - let categoryValues = []; - for (let categoryButton of categoryButtons) { - if (categoryButton.classList.contains("selected")) { - categoryValues.push(categoryButton.name.replace("category_", "")); - } - } - categoryValuesInput.value = categoryValues.join(","); - } - form.submit(); - }); - } - }); - -})(window, document, window.searxng); diff --git a/searx/static/themes/simple/src/less/animations.less b/searx/static/themes/simple/src/less/animations.less deleted file mode 100644 index 75c98308f..000000000 --- a/searx/static/themes/simple/src/less/animations.less +++ /dev/null @@ -1,19 +0,0 @@ -.dialog-modal { - animation-name: dialogmodal; - animation-duration: 0.13s; - - @keyframes dialogmodal { - 0% { - opacity: 0; - } - - 50% { - opacity: 0.5; - transform: translate(-50%, -50%) scale(1.05); - } - } -} - -input.checkbox-onoff[type="checkbox"]::before { - transition: left 0.25s; -} diff --git a/searx/static/themes/simple/src/less/autocomplete.less b/searx/static/themes/simple/src/less/autocomplete.less deleted file mode 100644 index 8285ff2c6..000000000 --- a/searx/static/themes/simple/src/less/autocomplete.less +++ /dev/null @@ -1,74 +0,0 @@ -/*! Autocomplete.js v2.6.3 | license MIT | (c) 2017, Baptiste Donaux | http://autocomplete-js.com */ - -.autocomplete { - position: absolute; - width: @search-width; - max-height: 0; - overflow-y: hidden; - .ltr-text-align-left(); - - .rounded-corners; - - &:active, - &:focus, - &:hover { - background-color: var(--color-autocomplete-background); - } - - &:empty { - display: none; - } - - > ul { - list-style-type: none; - margin: 0; - padding: 0; - - > li { - cursor: pointer; - padding: 0.5rem 1rem; - - &.active, - &:active, - &:focus, - &:hover { - background-color: var(--color-autocomplete-background-hover); - - a:active, - a:focus, - a:hover { - text-decoration: none; - } - } - - &.locked { - cursor: inherit; - } - } - } - - &.open { - display: block; - background-color: var(--color-autocomplete-background); - color: var(--color-autocomplete-font); - max-height: 32rem; - overflow-y: auto; - z-index: 5000; - margin-top: 3.5rem; - border-radius: 0.8rem; - - &:empty { - display: none; - } - } -} - -@media screen and (max-width: @phone) { - .autocomplete { - width: 100%; - - > ul > li { - padding: 1rem; - } - } -} diff --git a/searx/static/themes/simple/src/less/code.less b/searx/static/themes/simple/src/less/code.less deleted file mode 100644 index 6e838bf88..000000000 --- a/searx/static/themes/simple/src/less/code.less +++ /dev/null @@ -1,51 +0,0 @@ -@import "../generated/pygments.less"; - -.codelines { - margin: @results-margin 0 0 0; - padding: @result-padding 0 0 0; -} - -.code-highlight-sxng() { - .code-highlight { - pre { - overflow: auto; - margin: 0; - padding: 0 0 0.75rem 0; - } - - .linenos { - user-select: none; - cursor: default; - - &::selection { - background: transparent; /* WebKit/Blink Browsers */ - } - - &::-moz-selection { - background: transparent; /* Gecko Browsers */ - } - margin-right: 8px; - text-align: right; - } - - span.linenos { - color: var(--color-line-number); - } - } -} - -.code-highlight-sxng(); - -/// Dark Theme (autoswitch based on device pref) -@media (prefers-color-scheme: dark) { - :root.theme-auto { - .code-highlight-dark(); - .code-highlight-sxng(); - } -} - -// Dark Theme by preferences -:root.theme-dark { - .code-highlight-dark(); - .code-highlight-sxng(); -} diff --git a/searx/static/themes/simple/src/less/definitions.less b/searx/static/themes/simple/src/less/definitions.less deleted file mode 100644 index 7501305fc..000000000 --- a/searx/static/themes/simple/src/less/definitions.less +++ /dev/null @@ -1,304 +0,0 @@ -/* - * SearXNG, A privacy-respecting, hackable metasearch engine - * - * To change the colors of the site, simple edit this variables - */ - -/// Light Theme -:root { - /// Base Colors - --color-base-font: #444; - --color-base-font-rgb: 68, 68, 68; - --color-base-background: #fff; - --color-base-background-mobile: #f2f5f8; - --color-url-font: #334999; - --color-url-visited-font: #9822c3; - /// Header Colors - --color-header-background: #fdfbff; - --color-header-border: #ddd; - /// Footer Colors - --color-footer-background: #fdfbff; - --color-footer-border: #ddd; - /// Sidebar Colors - --color-sidebar-border: #ddd; - --color-sidebar-font: #000; - --color-sidebar-background: #fff; - /// BackToTop Colors - --color-backtotop-font: #444; - --color-backtotop-border: #ddd; - --color-backtotop-background: #fff; - /// Button Colors - --color-btn-background: #3050ff; - --color-btn-font: #fff; - --color-show-btn-background: #bbb; - --color-show-btn-font: #000; - /// Search Input Colors - --color-search-border: #bbb; - --color-search-shadow: 0 2px 8px rgb(34 38 46 / 25%); - --color-search-background: #fff; - --color-search-font: #222; - --color-search-background-hover: #3050ff; - /// Modal Colors - --color-error: #db3434; - --color-error-background: lighten(#db3434, 40%); - --color-warning: #dbba34; - --color-warning-background: lighten(#dbba34, 40%); - --color-success: #42db34; - --color-success-background: lighten(#42db34, 40%); - /// Categories Colors - --color-categories-item-selected-font: #3050ff; - --color-categories-item-border-selected: #3050ff; - /// Autocomplete Colors - --color-autocomplete-font: #000; - --color-autocomplete-border: #bbb; - --color-autocomplete-shadow: 0 2px 8px rgb(34 38 46 / 25%); - --color-autocomplete-background: #fff; - --color-autocomplete-background-hover: #e3e3e3; - /// Answer Colors - --color-answer-font: #444; // same as --color-base-font - --color-answer-background: #fff; - /// Results Colors - --color-result-background: #fff; - --color-result-border: #ddd; - --color-result-url-font: #000; - --color-result-vim-selected: #f7f7f7; - --color-result-vim-arrow: #000bbb; - --color-result-description-highlight-font: #000; - --color-result-link-font: #000bbb; - --color-result-link-font-highlight: #000bbb; - --color-result-link-visited-font: #9822c3; - --color-result-publishdate-font: #777; - --color-result-engines-font: #545454; - --color-result-search-url-border: #ddd; - --color-result-search-url-font: #000; - // Images Colors - --color-result-image-span-font: #444; - --color-result-image-span-font-selected: #fff; - --color-result-image-background: #fff; - /// Settings Colors - --color-settings-tr-hover: #ebebeb; - --color-settings-engine-description-font: #545454; - --color-settings-table-group-background: #0001; - /// Detail modal - --color-result-detail-font: #fff; - --color-result-detail-label-font: lightgray; - --color-result-detail-background: #242424; - --color-result-detail-hr: #555; - --color-result-detail-link: #8af; - --color-result-detail-loader-border: rgb(255 255 255 / 20%); - --color-result-detail-loader-borderleft: rgb(0 0 0 / 0%); - /// Toolkit Colors - --color-toolkit-badge-font: #fff; - --color-toolkit-badge-background: #545454; - --color-toolkit-kbd-font: #fff; - --color-toolkit-kbd-background: #000; - --color-toolkit-dialog-border: #ddd; - --color-toolkit-dialog-background: #fff; - --color-toolkit-tabs-label-border: #fff; - --color-toolkit-tabs-section-border: #ddd; - --color-toolkit-select-background: #e1e1e1; - --color-toolkit-select-border: #ddd; - --color-toolkit-select-background-hover: #bbb; - --color-toolkit-input-text-font: #222; - --color-toolkit-checkbox-onoff-off-background: #ddd; - --color-toolkit-checkbox-onoff-on-background: #ddd; - --color-toolkit-checkbox-onoff-on-mark-background: #3050ff; - --color-toolkit-checkbox-onoff-on-mark-color: #fff; - --color-toolkit-checkbox-onoff-off-mark-background: #aaa; - --color-toolkit-checkbox-onoff-off-mark-color: #fff; - --color-toolkit-checkbox-label-background: #ddd; - --color-toolkit-checkbox-label-border: #ddd; - --color-toolkit-checkbox-input-border: #3050ff; - --color-toolkit-engine-tooltip-border: #ddd; - --color-toolkit-engine-tooltip-background: #fff; - --color-toolkit-loader-border: rgb(0 0 0 / 20%); - --color-toolkit-loader-borderleft: rgb(255 255 255 / 0%); - --color-doc-code: #003; - --color-doc-code-background: #ddeaff; - /// Other misc colors - --color-bar-chart-primary: #5bc0de; - --color-bar-chart-secondary: #deb15b; - --color-image-resolution-background: rgb(0 0 0 / 50%); - --color-image-resolution-font: #fff; - --color-loading-indicator: rgb(255 255 255 / 20%); - --color-loading-indicator-gap: #fff; - --color-line-number: #64708d; - // Favicons Colors - --color-favicon-background-color: #ddd; - --color-favicon-border-color: #ccc; -} - -.dark-themes() { - /// Base Colors - --color-base-font: #bbb; - --color-base-font-rgb: 187, 187, 187; - --color-base-background: #222428; - --color-base-background-mobile: #222428; - --color-url-font: #8af; - --color-url-visited-font: #c09cd9; - /// Header Colors - --color-header-background: #1e1e22; - --color-header-border: #333; - /// Footer Colors - --color-footer-background: #1e1e22; - --color-footer-border: #333; - /// Sidebar Colors - --color-sidebar-border: #555; - --color-sidebar-font: #fff; - --color-sidebar-background: #292c34; - /// BackToTop Colors - --color-backtotop-font: #bbb; - --color-backtotop-border: #333; - --color-backtotop-background: #2b2e36; - /// Button Colors - --color-btn-background: #58f; - --color-btn-font: #222; - --color-show-btn-background: #555; - --color-show-btn-font: #fff; - /// Search Input Colors - --color-search-border: #555; - --color-search-shadow: 0 2px 8px rgb(34 38 46 / 25%); - --color-search-background: #2b2e36; - --color-search-font: #fff; - --color-search-background-hover: #58f; - /// Modal Colors - --color-error: #f55b5b; - --color-error-background: darken(#db3434, 40%); - --color-warning: #f1d561; - --color-warning-background: darken(#dbba34, 40%); - --color-success: #79f56e; - --color-success-background: darken(#42db34, 40%); - /// Categories Colors - --color-categories-item-selected-font: #58f; - --color-categories-item-border-selected: #58f; - /// Autocomplete Colors - --color-autocomplete-font: #fff; - --color-autocomplete-border: #555; - --color-autocomplete-shadow: 0 2px 8px rgb(34 38 46 / 25%); - --color-autocomplete-background: #2b2e36; - --color-autocomplete-background-hover: #1e1e22; - /// Answer Colors - --color-answer-font: #bbb; // same as --color-base-font - --color-answer-background: #26292f; - /// Results Colors - --color-result-background: #26292f; - --color-result-border: #333; - --color-result-url-font: #fff; - --color-result-vim-selected: #1f1f23cc; - --color-result-vim-arrow: #8af; - --color-result-description-highlight-font: #fff; - --color-result-link-font: #8af; - --color-result-link-font-highlight: #8af; - --color-result-link-visited-font: #c09cd9; - --color-result-publishdate-font: #888; - --color-result-engines-font: #a4a4a4; - --color-result-search-url-border: #555; - --color-result-search-url-font: #fff; - /// Detail modal : same as the light version - --color-result-detail-font: #fff; - --color-result-detail-label-font: lightgray; - --color-result-detail-background: #1a1a1c; - --color-result-detail-hr: #555; - --color-result-detail-link: #8af; - --color-result-detail-loader-border: rgb(255 255 255 / 20%); - --color-result-detail-loader-borderleft: rgb(0 0 0 / 0%); - // Images Colors - --color-result-image-span-font: #bbb; - --color-result-image-span-font-selected: #222; - --color-result-image-background: #222; - /// Settings Colors - --color-settings-tr-hover: #2c2c32; - --color-settings-engine-description-font: darken(#dcdcdc, 30%); - --color-settings-table-group-background: #1b1b21; - /// Toolkit Colors - --color-toolkit-badge-font: #fff; - --color-toolkit-badge-background: #555; - --color-toolkit-kbd-font: #000; - --color-toolkit-kbd-background: #fff; - --color-toolkit-dialog-border: #555; - --color-toolkit-dialog-background: #1e1e22; - --color-toolkit-tabs-label-border: #222; - --color-toolkit-tabs-section-border: #555; - --color-toolkit-select-background: #313338; - --color-toolkit-select-border: #555; - --color-toolkit-select-background-hover: #373b49; - --color-toolkit-input-text-font: #fff; - --color-toolkit-checkbox-onoff-off-background: #313338; - --color-toolkit-checkbox-onoff-on-background: #313338; - --color-toolkit-checkbox-onoff-on-mark-background: #58f; - --color-toolkit-checkbox-onoff-on-mark-color: #222; - --color-toolkit-checkbox-onoff-off-mark-background: #ddd; - --color-toolkit-checkbox-onoff-off-mark-color: #222; - --color-toolkit-checkbox-label-background: #222; - --color-toolkit-checkbox-label-border: #333; - --color-toolkit-checkbox-input-border: #58f; - --color-toolkit-engine-tooltip-border: #333; - --color-toolkit-engine-tooltip-background: #222; - --color-toolkit-loader-border: rgb(255 255 255 / 20%); - --color-toolkit-loader-borderleft: rgb(0 0 0 / 0%); - --color-doc-code: #ddd; - --color-doc-code-background: #4d5a6f; - // Favicons Colors - --color-favicon-background-color: #ddd; - --color-favicon-border-color: #ccc; -} - -.black-themes() { - --color-base-background: #000; - --color-base-background-mobile: #000; - --color-header-background: #000; - --color-footer-background: #000; - --color-sidebar-background: #000; -} - -/// Dark Theme (autoswitch based on device pref) -@media (prefers-color-scheme: dark) { - :root.theme-auto { - .dark-themes(); - } -} - -// Dark Theme by preferences -:root.theme-dark { - .dark-themes(); -} - -:root.theme-black { - .dark-themes(); - .black-themes(); -} - -/// General Size -@results-width: 45rem; -@results-sidebar-width: 25rem; -@results-offset: 10rem; -@results-tablet-offset: 0.5rem; -@results-gap: 5rem; -@results-margin: 0.125rem; -@result-padding: 1rem; -@results-image-row-height: 12rem; -@results-image-row-height-phone: 10rem; -@search-width: 44rem; -// heigh of #search, see detail.less -@search-height: 13rem; - -/// Device Size -/// @desktop > @tablet -@tablet: 79.75em; // see https://github.com/searxng/searxng/issues/874 -@phone: 50em; -@small-phone: 35em; -@ultra-small-phone: 20rem; - -/// From style.less -@stacked-bar-chart: rgb(0, 0, 0); - -/// Load fonts from this directory. -@icon-font-path: "../../../fonts/"; -//** File name for all font files. -@icon-font-name: "glyphicons-halflings-regular"; -//** Element ID within SVG icon file. -@icon-font-svg-id: "glyphicons_halflingsregular"; - -// decoration of the select HTML elements -@select-light-svg-path: "../svg/select-light.svg"; -@select-dark-svg-path: "../svg/select-dark.svg"; diff --git a/searx/static/themes/simple/src/less/detail.less b/searx/static/themes/simple/src/less/detail.less deleted file mode 100644 index fd5cd8e05..000000000 --- a/searx/static/themes/simple/src/less/detail.less +++ /dev/null @@ -1,253 +0,0 @@ -#main_results #results.image-detail-open.only_template_images { - width: min(98%, 59.25rem) !important; -} - -#main_results #results.only_template_images.image-detail-open #backToTop { - .ltr-left(56.75rem) !important; - .ltr-right(inherit); -} - -article.result-images .detail { - display: none; -} - -#results.image-detail-open article.result-images[data-vim-selected] .detail { - display: flex; - flex-direction: column; - position: fixed; - .ltr-left(60rem); - .ltr-right(0); - top: @search-height; - transition: top 0.064s ease-in 0s; - bottom: 0; - background: var(--color-result-detail-background); - border: 1px solid var(--color-result-detail-background); - z-index: 1000; - padding: 4rem 3rem 3rem 3rem; - - a.result-images-source { - display: block; - flex: 1; - text-align: left; - width: 100%; - border: none; - text-decoration: none; - - img { - padding: 0; - margin: 0; - border: none; - object-fit: contain; - width: inherit; - height: inherit; - max-width: 100%; - min-height: inherit; - max-height: calc(100vh - 25rem - 7rem); - background: inherit; - } - } - - .result-images-labels { - color: var(--color-result-detail-font); - height: 19rem; - - hr { - border-top: 1px solid var(--color-result-detail-hr); - border-bottom: none; - } - - h4 { - height: 2rem; - overflow: hidden; - text-overflow: ellipsis; - font-size: 0.9rem; - margin-bottom: 0; - } - - p { - color: var(--color-result-detail-label-font); - font-size: 0.9rem; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - margin: 0.8rem 0; - - span { - display: inline-block; - width: 12rem; - } - } - - h4, - p, - a { - .ltr-text-align-left(); - } - - p.result-content { - height: 2rem; - line-height: unset; - overflow: hidden; - text-overflow: ellipsis; - } - - p.result-url { - white-space: nowrap; - overflow: hidden hidden; - text-overflow: ellipsis; - } - - p.result-content:hover, - p.result-url:hover { - position: relative; - overflow: inherit !important; - background: var(--color-result-detail-background); - text-overflow: inherit !important; - } - - a, - a:visited, - a:hover, - a:active { - color: var(--color-result-detail-link); - } - - a:hover { - text-decoration: underline; - } - } - - a.result-detail-close { - top: 1rem; - .ltr-left(1rem); - padding: 0.4rem; - } - - a.result-detail-previous { - top: 1rem; - .ltr-right(6rem); - // center the icon by moving it slightly on the left - padding-top: 0.4rem; - .ltr-padding-right(0.5rem); - padding-bottom: 0.4rem; - .ltr-padding-left(0.3rem); - } - - a.result-detail-next { - top: 1rem; - .ltr-right(2rem); - padding: 0.4rem; - } - - a.result-detail-close, - a.result-detail-next, - a.result-detail-previous { - border-radius: 50%; - display: block; - width: 1.5rem; - height: 1.5rem; - position: absolute; - filter: opacity(40%); - z-index: 1200; - - span { - display: block; - width: 1.5rem; - height: 1.5rem; - text-align: center; - } - } - - a.result-detail-next, - a.result-detail-previous { - span::before { - // vertical center small icons - vertical-align: sub; - } - } - - a.result-detail-close, - a.result-detail-close:visited, - a.result-detail-close:hover, - a.result-detail-close:active, - a.result-detail-previous, - a.result-detail-previous:visited, - a.result-detail-previous:hover, - a.result-detail-previous:active, - a.result-detail-next, - a.result-detail-next:visited, - a.result-detail-next:hover, - a.result-detail-next:active { - color: var(--color-result-detail-font); - background: var(--color-result-detail-background); - border: 1px solid var(--color-result-detail-font); - } - - a.result-detail-close:focus, - a.result-detail-close:hover, - a.result-detail-previous:focus, - a.result-detail-previous:hover, - a.result-detail-next:focus, - a.result-detail-next:hover { - filter: opacity(80%); - } - - .loader { - position: absolute; - top: 1rem; - .ltr-right(50%); - border-top: 0.5em solid var(--color-result-detail-loader-border); - border-right: 0.5em solid var(--color-result-detail-loader-border); - border-bottom: 0.5em solid var(--color-result-detail-loader-border); - border-left: 0.5em solid var(--color-result-detail-loader-borderleft); - } -} - -#results.image-detail-open.scrolling article.result-images[data-vim-selected] .detail { - top: 0; - - a.result-images-source img { - max-height: calc(100vh - 25rem); - } -} - -@media screen and (max-width: @tablet) { - #results.image-detail-open article.result-images[data-vim-selected] .detail { - top: 0; - .ltr-left(0); - - a.result-images-source { - display: flex; - flex-direction: column; - justify-content: center; - - img { - width: 100%; - max-height: calc(100vh - 24rem); - } - } - - a.result-detail-next { - .ltr-right(1rem); - } - } -} - -@media screen and (max-width: @phone) { - #results.image-detail-open article.result-images[data-vim-selected] .detail { - top: 0; - .ltr-left(0); - padding: 1rem; - - a.result-images-source img { - width: 100%; - max-height: calc(100vh - 20rem); - margin: 0; - } - - .result-images-labels p span { - width: inherit; - .ltr-margin-right(1rem); - } - } -} diff --git a/searx/static/themes/simple/src/less/embedded.less b/searx/static/themes/simple/src/less/embedded.less deleted file mode 100644 index bd7b89ea6..000000000 --- a/searx/static/themes/simple/src/less/embedded.less +++ /dev/null @@ -1,33 +0,0 @@ -iframe[src^="https://w.soundcloud.com"] { - height: 120px; -} - -iframe[src^="https://www.deezer.com"] { - // The real size is 92px, but 94px are needed to avoid an inner scrollbar of - // the embedded HTML. - height: 94px; -} - -iframe[src^="https://www.mixcloud.com"] { - // the embedded player from mixcloud has some quirks: initial there is an - // issue with an image URL that is blocked since it is an a Cross-Origin - // request. The alternative text (Mixcloud Logo then cause an - // scrollbar in the inner of the iframe we can't avoid. Another quirk comes - // when pressing the play button, sometimes the shown player has an height of - // 200px, sometimes 250px. - height: 250px; -} - -iframe[src^="https://bandcamp.com/EmbeddedPlayer"] { - // show playlist - height: 350px; -} - -iframe[src^="https://bandcamp.com/EmbeddedPlayer/track"] { - // hide playlist - height: 120px; -} - -iframe[src^="https://genius.com/songs"] { - height: 65px; -} diff --git a/searx/static/themes/simple/src/less/index.less b/searx/static/themes/simple/src/less/index.less deleted file mode 100644 index 8590d0c3b..000000000 --- a/searx/static/themes/simple/src/less/index.less +++ /dev/null @@ -1,51 +0,0 @@ -#main_index { - margin-top: 26vh; -} - -.index { - text-align: center; - - .title { - background: url('../img/searxng.png') no-repeat; - min-height: 4rem; - margin: 4rem auto; - background-position: center; - background-size: contain; - } - - h1 { - font-size: 4em; - visibility: hidden; - } - - #search, - #search_header { - margin: 0 auto; - background: inherit; - border: inherit; - padding: 0; - display: block; - } - - .search_filters { - display: block; - margin: 1em 0; - } - - .category label { - padding: 6px 10px; - border-bottom: initial !important; - } -} - -@media screen and (max-width: @tablet) { - div.title { - h1 { - font-size: 1em; - } - } - - #main_index { - margin-top: 6em; - } -} diff --git a/searx/static/themes/simple/src/less/info.less b/searx/static/themes/simple/src/less/info.less deleted file mode 100644 index f354135d2..000000000 --- a/searx/static/themes/simple/src/less/info.less +++ /dev/null @@ -1,10 +0,0 @@ -.info-page { - code { - font-family: monospace; - .rounded-corners-tiny; - background-color: var(--color-doc-code-background); - color: var(--color-doc-code); - padding: 0.2rem; - border: 0 none; - } -} diff --git a/searx/static/themes/simple/src/less/mixins.less b/searx/static/themes/simple/src/less/mixins.less deleted file mode 100644 index a4bae7128..000000000 --- a/searx/static/themes/simple/src/less/mixins.less +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -// Mixins -.text-size-adjust (@property: 100%) { - -webkit-text-size-adjust: @property; - -ms-text-size-adjust: @property; - -moz-text-size-adjust: @property; - text-size-adjust: @property; -} - -.rounded-corners (@radius: 10px) { - border-radius: @radius; -} - -.rounded-right-corners (@radius: 0 10px 10px 0) { - border-radius: @radius; -} - -.rounded-corners-tiny (@radius: 5px) { - border-radius: @radius; -} - -// disable user selection -.disable-user-select () { - -webkit-touch-callout: none; - user-select: none; -} - -.show-content-button() { - padding: 5px 10px; - .rounded-corners-tiny; - background: var(--color-show-btn-background); - color: var(--color-show-btn-font); - cursor: pointer; - - &:hover { - background: var(--color-btn-background); - color: var(--color-btn-font); - } -} diff --git a/searx/static/themes/simple/src/less/new_issue.less b/searx/static/themes/simple/src/less/new_issue.less deleted file mode 100644 index e10a2791c..000000000 --- a/searx/static/themes/simple/src/less/new_issue.less +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later -.stats_endpoint { - .github-issue-button { - display: block; - font-size: 16px; - } - - .issue-hide { - display: none; - } - - input[type=checked] { - position: absolute; - } - - label { - margin: 1rem 1rem 1rem 0; - } - - .step_content { - margin: 1rem 1rem 1rem 2rem; - } - - .step1, - .step2 { - visibility: hidden; - } - - .step1_delay { - transition: visibility 0s linear 4s; - } - - #step1:checked ~ .step1, - #step2:checked ~ .step2 { - visibility: visible; - } -} diff --git a/searx/static/themes/simple/src/less/preferences.less b/searx/static/themes/simple/src/less/preferences.less deleted file mode 100644 index 497b2077a..000000000 --- a/searx/static/themes/simple/src/less/preferences.less +++ /dev/null @@ -1,233 +0,0 @@ -table { - border-collapse: collapse; - - th, - td { - text-align: center; - padding: 1rem 0.5rem; - .ltr-text-align-left(); - } - - tr.pref-group th { - font-weight: normal; - .ltr-text-align-left(); - background: var(--color-settings-table-group-background); - } -} - -#main_preferences { - form { - width: 100%; - } - - fieldset { - margin: 8px; - border: none; - } - - legend { - margin: 0; - padding: 5px 0 0 0; - display: block; - .ltr-float-left(); - width: 300px; - } - - input[type="text"] { - width: 13.25rem; - color: var(--color-toolkit-input-text-font); - border: none; - background: none repeat scroll 0 0 var(--color-toolkit-select-background); - padding: 0.2rem 0.4rem; - height: 2rem; - .rounded-corners-tiny; - - &:hover, - &:focus { - background-color: var(--color-toolkit-select-background-hover); - } - } - - div.pref-group { - width: 100%; - font-weight: normal; - padding: 1rem 0.5rem; - .ltr-text-align-left(); - background: var(--color-settings-table-group-background); - } - - .value { - margin: 0; - padding: 0; - .ltr-float-left(); - width: 15em; - - select, - input[type="text"] { - font-size: inherit !important; - margin-top: 0; - .ltr-margin-right(1rem); - margin-bottom: 0; - .ltr-margin-left(0); - } - - select { - width: 14rem; - } - - select:focus, - input:focus { - outline: none; - box-shadow: 0 0 1px 1px var(--color-btn-background); - } - } - - .description { - margin: 0; - padding: 5px 0 0 0; - .ltr-float-right(); - width: 50%; - color: var(--color-settings-engine-description-font); - font-size: 90%; - } - - .bang { - .ltr-text-align-left(); - .rounded-corners-tiny; - background-color: var(--color-doc-code-background); - color: var(--color-doc-code); - padding: 0.2rem; - border: 0 none; - } - - .category { - .ltr-margin-right(0.5rem); - - label { - border: 2px solid transparent; - padding: 0.2rem 0.4rem; - .rounded-corners-tiny; - } - } - - .category input[type="checkbox"]:checked + label { - border: 2px solid var(--color-categories-item-border-selected); - } - - table.table_engines { - th.name { - /* stylelint-disable */ - label { - cursor: pointer; - } - /* stylelint-enable */ - - .engine-tooltip { - margin-top: 1.8rem; - .ltr-left(calc((100% - 85em) / 2 + 10em)); - max-width: 40rem; - - .engine-description { - margin-top: 0.5rem; - } - - .bang { - margin: 0.3rem; - } - } - } - - .checkbox-col, - .name, - .shortcut { - .ltr-text-align-left(); - } - } - - table.cookies { - width: 100%; - direction: ltr; - - th, - td { - text-align: left; - font-family: monospace; - font-size: 1rem; - padding: 0.5em; - vertical-align: top; - } - - td:first-child { - word-break: keep-all; - width: 14rem; - padding-right: 1rem; - } - - td:last-child { - word-break: break-all; - } - - & > tbody > tr:nth-child(even) > th, - & > tbody > tr:nth-child(even) > td { - background-color: var(--color-settings-tr-hover); - } - } - - .preferences_back { - background: none repeat scroll 0 0 var(--color-btn-background); - color: var(--color-btn-font); - border: 0 none; - .rounded-corners; - - cursor: pointer; - display: inline-block; - margin: 2px 4px; - padding: 0.7em; - - a { - color: var(--color-settings-return-font); - } - - a::first-letter { - text-transform: uppercase; - } - } - - #toggle-all-engines-container { - width: max-content; - margin-left: auto; - } - - div.selectable_url { - pre { - width: 100%; - } - } - - #copy-hash-container { - display: flex; - align-items: center; - gap: 0.5rem; - - div.selectable_url { - pre { - width: auto; - flex-grow: 1; - } - } - } - - #pref-hash-input { - width: 100%; - } -} - -@media screen and (max-width: @tablet) { - .preferences_back { - clear: both; - } - - .engine-tooltip { - .ltr-left(10em) !important; - } -} diff --git a/searx/static/themes/simple/src/less/result_templates.less b/searx/static/themes/simple/src/less/result_templates.less deleted file mode 100644 index afabdf322..000000000 --- a/searx/static/themes/simple/src/less/result_templates.less +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -.osm-map-box { - height: 300px; - width: 100%; - margin: 10px 0; -} diff --git a/searx/static/themes/simple/src/less/rss.less b/searx/static/themes/simple/src/less/rss.less deleted file mode 100644 index 0bc6622e3..000000000 --- a/searx/static/themes/simple/src/less/rss.less +++ /dev/null @@ -1,45 +0,0 @@ -@import (inline) "../../node_modules/normalize.css/normalize.css"; -@import "definitions.less"; - -.text-size-adjust (@property: 100%) { - -webkit-text-size-adjust: @property; - -ms-text-size-adjust: @property; - -moz-text-size-adjust: @property; - text-size-adjust: @property; -} - -// Reset padding and margin -html, -body, -main { - padding: 0; - margin: 0; -} - -html { - font-family: sans-serif; - font-size: 0.9em; - .text-size-adjust; - - color: var(--color-base-font); - background-color: var(--color-base-background); - - scroll-behavior: smooth; -} - -body { - margin-inline: 1rem; -} - -a { - text-decoration: none; - color: var(--color-url-font); - - &:visited { - color: var(--color-url-visited-font); - - .highlight { - color: var(--color-url-visited-font); - } - } -} diff --git a/searx/static/themes/simple/src/less/search.less b/searx/static/themes/simple/src/less/search.less deleted file mode 100644 index a46e4bf06..000000000 --- a/searx/static/themes/simple/src/less/search.less +++ /dev/null @@ -1,393 +0,0 @@ -/* -* SearXNG, A privacy-respecting, hackable metasearch engine -*/ - -#search { - padding: 0; - margin: 0; -} - -#search_header { - padding-top: 1.5em; - .ltr-padding-right(2em); - .ltr-padding-left(@results-offset - 3rem); - margin: 0; - background: var(--color-header-background); - border-bottom: 1px solid var(--color-header-border); - display: grid; - gap: 1rem 1.2rem; - grid-template-columns: 3rem 1fr; - grid-template-areas: - "logo search" - "spacer categories"; -} - -.category_checkbox, -.category_button { - display: inline-block; - position: relative; - .ltr-margin-right(1rem); - padding: 0; -} - -.category_checkbox { - input { - display: none; - } - - label { - svg { - padding-right: 0.2rem; - } - - cursor: pointer; - padding: 0.2rem 0; - display: inline-flex; - text-transform: capitalize; - font-size: 0.9em; - border-bottom: 2px solid transparent; - .disable-user-select; - - div.category_name { - margin: auto 0; - } - } - - input[type="checkbox"]:checked + label { - color: var(--color-categories-item-selected-font); - border-bottom: 2px solid var(--color-categories-item-border-selected); - } -} - -button.category_button { - background-color: inherit; - color: var(--color-base-font); - cursor: pointer; - padding: 0.2rem 0; - display: inline-flex; - align-items: center; - text-transform: capitalize; - font-size: 0.9em; - border: none; - border-bottom: 2px solid transparent; - - svg { - padding-right: 0.2rem; - } - - &.selected, - &:active { - color: var(--color-categories-item-selected-font); - border-bottom: 2px solid var(--color-categories-item-border-selected); - } -} - -// only used when JavaScript is disabled -.no-js #categories_container:has(button.category_button:focus-within) button.category_button { - &.selected { - color: var(--color-base-font); - border-bottom: none; - } - - &:focus-within { - color: var(--color-categories-item-selected-font); - border-bottom: 2px solid var(--color-categories-item-border-selected); - } -} - -#search_logo { - padding: 0.5rem 10px 0 10px; - grid-area: logo; - display: flex; - align-items: center; - justify-content: center; - - svg { - flex: 1; - width: 30px; - height: 30px; - margin: 0.5rem 0 auto 0; - } -} - -.search_categories { - grid-area: categories; - - .help { - display: none; - } - - &:hover .help { - display: block; - position: absolute; - background: var(--color-base-background); - padding: 1rem 0.6rem 0.6rem 0; - z-index: 1000; - width: 100%; - left: -0.1rem; - } -} - -#search_view { - padding: 0.5rem 0.3rem 0 0.5rem; - grid-area: search; - - body.results_endpoint & { - padding: 0.5rem 2.8rem 0 0; - } -} - -.search_box { - border-radius: 0.8rem; - width: @search-width; - display: inline-flex; - flex-direction: row; - white-space: nowrap; - box-shadow: var(--color-search-shadow); -} - -#clear_search { - display: block; - border-collapse: separate; - box-sizing: border-box; - width: 1.8rem; - margin: 0; - padding: 0.8rem 0.2rem; - background: none repeat scroll 0 0 var(--color-search-background); - border: none; - outline: none; - color: var(--color-search-font); - font-size: 1.1rem; - z-index: 1000; - - &:hover { - color: var(--color-search-background-hover); - } - - &.empty * { - display: none; - } -} - -html.no-js #clear_search.hide_if_nojs { - display: none; -} - -#q, -#send_search { - display: block; - margin: 0; - padding: 0.8rem; - background: none repeat scroll 0 0 var(--color-search-background); - border: none; - outline: none; - color: var(--color-search-font); - font-size: 1.1rem; - z-index: 100; -} - -#q { - width: 100%; - .ltr-padding-left(1rem); - .ltr-padding-right(0) !important; - .ltr-rounded-left-corners(0.8rem); -} - -#q::-ms-clear, -#q::-webkit-search-cancel-button { - display: none; -} - -#send_search { - .ltr-rounded-right-corners(0.8rem); - - &:hover { - cursor: pointer; - background-color: var(--color-search-background-hover); - color: var(--color-search-background); - } -} - -.no-js #clear_search, -.no-js #send_search { - width: auto !important; - .ltr-border-left(1px solid var(--color-search-border)); -} - -.search_filters { - margin-top: 0.6rem; - .ltr-margin-right(0); - margin-bottom: 0; - .ltr-margin-left(@results-offset + 0.6rem); - display: flex; - overflow-x: auto; - overscroll-behavior-inline: contain; - - select { - background-color: inherit; - - &:hover, - &:focus { - color: var(--color-base-font); - } - } -} - -@media screen and (max-width: @tablet) { - #search_header { - padding: 1.5em @results-tablet-offset 0 @results-tablet-offset; - column-gap: @results-tablet-offset; - } - - .search_filters { - margin-top: 0.6rem; - .ltr-margin-right(0); - margin-bottom: 0; - .ltr-margin-left(@results-tablet-offset + 3rem); - } - - #categories { - font-size: 90%; - clear: both; - } -} - -@media screen and (max-width: @tablet) and (hover: none) { - #main_index, - #main_results { - #categories_container { - width: max-content; - - .category_checkbox { - display: inline-block; - width: auto; - } - } - - #categories { - width: 100%; - .ltr-text-align-left(); - overflow: scroll hidden; - -webkit-overflow-scrolling: touch; - } - } -} - -@media screen and (max-width: @phone) { - #search_header { - width: 100%; - margin: 0; - padding: 0.1rem 0 0 0; - gap: 0 0; - grid-template-areas: - "logo search" - "categories categories"; - } - - .search_logo { - padding: 0; - } - - .search_box { - width: 98%; - display: flex; - } - - #q { - width: 100%; - flex: 1; - } - - .search_filters { - margin: 0 10px; - padding: 0.5rem 0; - } - - .category { - display: inline-block; - width: auto; - margin: 0; - - svg { - display: none; - } - } - - .category_checkbox { - label { - padding: 1rem !important; - margin: 0 !important; - } - } - - .category_button { - padding: 1rem !important; - margin: 0 !important; - } - - #search_view:focus-within { - display: block; - background-color: var(--color-search-background); - position: absolute; - top: 0; - height: 100%; - width: 100%; - z-index: 2000; - - .search_box { - border-bottom: 1px solid var(--color-search-border); - width: 100%; - border-radius: 0; - box-shadow: none; - - #send_search { - .ltr-margin-right(0) !important; // Delete when send_search button is disabled on mobile. - } - - * { - border: none; - border-radius: 0; - box-shadow: none; - } - } - } - - #main_results #q:placeholder-shown ~ #send_search { - .ltr-margin-right(2.6rem); - transition: margin 0.1s; - } -} - -@media screen and (max-width: @ultra-small-phone) { - #search_header { - grid-template-areas: - "search search" - "categories categories"; - } - - #search_logo { - display: none; - } -} - -#categories { - .disable-user-select; - - &::-webkit-scrollbar { - width: 0; - height: 0; - } -} - -#categories_container { - position: relative; -} - -.favicon img { - height: 1.5rem; - width: 1.5rem; - border-radius: 10%; - background-color: var(--color-favicon-background-color); - border: 1px solid var(--color-favicon-border-color); - display: flex; -} diff --git a/searx/static/themes/simple/src/less/stats.less b/searx/static/themes/simple/src/less/stats.less deleted file mode 100644 index 1e823f7c9..000000000 --- a/searx/static/themes/simple/src/less/stats.less +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -.engine-stats { - border-spacing: 0; - border-collapse: collapse; - - tr td, - tr th { - border-bottom: 1px solid var(--color-result-border); - padding: 0.25rem; - } - - table.engine-tooltip { - border-spacing: 0; - border-collapse: collapse; - - td, - th { - border: none; - } - } - - .engine-name { - width: 20rem; - } - - .engine-score { - width: 7rem; - text-align: right; - } - - .engine-reliability { - text-align: right; - } -} - -table.engine-error th.engine-error-type, -table.engine-error td.engine-error-type, -failed-test { - width: 10rem; -} - -.engine-errors { - margin-top: 3rem; - - table.engine-error { - max-width: 1280px; - margin: 1rem 0 3rem 0; - border: 1px solid var(--color-result-border); - .ltr-text-align-left(); - - tr th, - tr td { - padding: 0.5rem; - } - - & span.log_parameters { - border-right: 1px solid solid var(--color-result-border); - padding: 0 1rem 0 0; - margin: 0 0 0 0.5rem; - } - } -} - -.bar-chart-value { - width: 3em; - display: inline-block; - text-align: right; - padding-right: 0.5rem; -} - -.bar-chart-graph { - width: calc(100% - 5rem); - display: inline-block; -} - -.bar-chart-bar { - border: 3px solid var(--color-bar-chart-primary); - margin: 1px 0; -} - -.bar-chart-serie1 { - border: 3px solid var(--color-bar-chart-primary); - margin: 1px 0; - float: left; -} - -.bar-chart-serie2 { - border: 3px solid var(--color-bar-chart-secondary); - margin: 1px 0; - float: left; -} - -.bar0 { - width: 0; - border: 0; -} - -.generate-bar(100); - -.generate-bar(@n, @i: 1) when (@i =< @n) { - .bar@{i} { - width: (@i * 100% / @n); - } - .generate-bar(@n, (@i + 1)); -} diff --git a/searx/static/themes/simple/src/less/style-center.less b/searx/static/themes/simple/src/less/style-center.less deleted file mode 100644 index 3618bed86..000000000 --- a/searx/static/themes/simple/src/less/style-center.less +++ /dev/null @@ -1,118 +0,0 @@ -/* ---center-page-width overrides the less variable @results-width when the results are centered -see the CSS rules for #results in style.less ( grid-template-columns and gap). - -In this file, the --center-page-width values comes from the Oscar theme (Bootstrap 3). - -All rules starts with ".center-alignment-yes #main_results" to be enabled only -on the /search URL and when the "center alignment" preference is enabled. -*/ - -@media screen and (min-width: @phone) { - .center-alignment-yes #main_results { - --center-page-width: 48rem; - } -} - -@media screen and (width >= 62rem) { - .center-alignment-yes #main_results { - --center-page-width: 60rem; - } -} - -@media screen and (min-width: @tablet) { - .center-alignment-yes #main_results { - --center-page-width: 73rem; - } -} - -@media screen and (min-width: @phone) and (max-width: @tablet) { - // any change must be reset in @media screen and (min-width: @tablet) { ... } - .center-alignment-yes #main_results { - #results { - grid-template-columns: 60% calc(40% - @results-gap); - margin-left: 0; - margin-right: 0; - } - - #urls { - .ltr-margin-left(3rem); - } - - #sidebar { - .ltr-margin-right(1rem); - } - - #backToTop { - .ltr-left(calc(60% + 1rem)); - } - } -} - -@media screen and (min-width: @tablet) { - .center-alignment-yes #main_results { - display: flex; - flex-direction: column; - align-items: center; - - #search { - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - } - - #search_header { - grid-template-columns: calc(50% - 4.5rem - var(--center-page-width) / 2) 3rem var(--center-page-width); - grid-template-areas: "na logo search" "na spacer categories"; - column-gap: 1.2rem; // from search.less - width: 100%; - padding-left: 0; - padding-right: 0; - } - - .search_filters { - .ltr-margin-left(0.5rem); - width: var(--center-page-width); - } - - #results { - // from style.less (when screen width = @tablet, reset layout from tablet) - .ltr-margin-right(2rem); - .ltr-margin-left(@results-offset); - // - - &.only_template_images, - &.image-detail-open { - // * grid-template-columns and .ltr-margin-left are set in style.less - // * With .image-detail-open.only_template_images, the width is set in detail.less - // * #results is going to be centered because of the #main_results rules, - // align-self aligns the results on the left or right according to the language. - align-self: flex-start; - } - - &:not(.only_template_images, .image-detail-open) { - // the gap is set in style.less - .ltr-margin-left(1.5rem); - grid-template-columns: calc(var(--center-page-width) - @results-gap - @results-sidebar-width) @results-sidebar-width; - - #backToTop { - .ltr-left(calc(50% - @results-sidebar-width - @results-gap + 1rem + var(--center-page-width) / 2)); - } - } - - .result .content { - max-width: inherit; - } - } - - // from style.less (when screen width = @tablet, reset layout from tablet) - #urls { - .ltr-margin-left(0); - } - - #sidebar { - .ltr-margin-right(0); - } - } -} diff --git a/searx/static/themes/simple/src/less/style-ltr.less b/searx/static/themes/simple/src/less/style-ltr.less deleted file mode 100644 index 6f7218b02..000000000 --- a/searx/static/themes/simple/src/less/style-ltr.less +++ /dev/null @@ -1,85 +0,0 @@ -.ltr-left(@offset) { - left: @offset; -} - -.ltr-right(@offset) { - right: @offset; -} - -.ltr-margin-right(@offset) { - margin-right: @offset; -} - -.ltr-margin-left(@offset) { - margin-left: @offset; -} - -.ltr-border-right(@offset) { - border-right: @offset; -} - -.ltr-border-left(@offset) { - border-left: @offset; -} - -.ltr-padding-right(@offset) { - padding-right: @offset; -} - -.ltr-padding-left(@offset) { - padding-left: @offset; -} - -.ltr-float-left() { - float: left; -} - -.ltr-float-right() { - float: right; -} - -.ltr-text-align-right() { - text-align: right; -} - -.ltr-rounded-left-corners(@radius) { - border-radius: @radius 0 0 @radius; -} - -.ltr-rounded-top-left-corners(@radius) { - border-radius: @radius 0 0 0; -} - -.ltr-rounded-bottom-left-corners(@radius) { - border-radius: 0 0 0 @radius; -} - -.ltr-rounded-right-corners(@radius) { - border-radius: 0 @radius @radius 0; -} - -.ltr-rounded-top-right-corners(@radius) { - border-radius: 0 @radius 0 0; -} - -.ltr-rounded-bottom-right-corners(@radius) { - border-radius: 0 0 @radius 0; -} - -.ltr-text-align-left() { - text-align: left; -} - -.ltr-border-left-width(@offset) { - border-left-width: @offset; -} - -.ltr-border-right-width(@offset) { - border-right-width: @offset; -} - -.ltr-transform() { - transform: scale(1, 1); -} - -@import "style.less"; diff --git a/searx/static/themes/simple/src/less/style-rtl.less b/searx/static/themes/simple/src/less/style-rtl.less deleted file mode 100644 index 8e2634d34..000000000 --- a/searx/static/themes/simple/src/less/style-rtl.less +++ /dev/null @@ -1,159 +0,0 @@ -.ltr-left(@offset) { - right: @offset; -} - -.ltr-right(@offset) { - left: @offset; -} - -.ltr-margin-right(@offset) { - margin-left: @offset; -} - -.ltr-margin-left(@offset) { - margin-right: @offset; -} - -.ltr-border-right(@offset) { - border-left: @offset; -} - -.ltr-border-left(@offset) { - border-right: @offset; -} - -.ltr-padding-right(@offset) { - padding-left: @offset; -} - -.ltr-padding-left(@offset) { - padding-right: @offset; -} - -.ltr-float-left() { - float: right; -} - -.ltr-float-right() { - float: left; -} - -.ltr-text-align-right() { - text-align: left; -} - -.ltr-rounded-left-corners(@radius) { - border-radius: 0 @radius @radius 0; -} - -.ltr-rounded-top-left-corners(@radius) { - border-radius: 0 @radius 0 0; -} - -.ltr-rounded-bottom-left-corners(@radius) { - border-radius: 0 0 @radius 0; -} - -.ltr-rounded-right-corners(@radius) { - border-radius: @radius 0 0 @radius; -} - -.ltr-rounded-top-right-corners(@radius) { - border-radius: @radius 0 0 0; -} - -.ltr-rounded-bottom-right-corners(@radius) { - border-radius: 0 0 0 @radius; -} - -.ltr-text-align-left() { - text-align: right; -} - -.ltr-border-left-width(@offset) { - border-right-width: @offset; -} - -.ltr-border-right-width(@offset) { - border-left-width: @offset; -} - -.ltr-transform() { - transform: scale(-1, 1); -} - -@import "style.less"; - -#q, -#sidebar .infobox dt bdi { - direction: rtl; -} - -// URL are displayed LTR but align on the right -#urls { - direction: initial; - text-align: right; - - .result .url_header { - direction: rtl; - } - - .result .url_wrapper { - justify-content: end; - } -} - -// Image flexbox -#main_results div#results.only_template_images #urls { - direction: rtl; -} - -// Image detail -#results.image-detail-open article.result-images[data-vim-selected] .detail .result-images-labels p { - direction: rtl; - - &.result-url { - // Display URL using the LTR direction - direction: ltr; - - span { - // And put the label on the right - direction: rtl; - float: right; - } - } -} - -// select HTML element -@supports ((background-position-x: 100%) and ((appearance: none) or (-webkit-appearance: none) or (-moz-appearance: none))) { - select { - border-width: 0 0 0 2rem; - background-position-x: -2rem; - } -} - -// vim hotkey helps is not translated -#vim-hotkeys-help table { - direction: ltr; - text-align: left; -} - -// Logo on the right -#main_preferences h1, -#main_stats h1 { - background-position-x: 100%; -} - -// patch of stats.less -.bar-chart-serie1, -.bar-chart-serie2 { - float: right; -} - -.engine-stats .engine-name, -.engine-stats .engine-score, -.engine-stats .result-count, -.engine-stats .response-time, -.engine-stats .engine-reliability { - text-align: right; -} diff --git a/searx/static/themes/simple/src/less/style.less b/searx/static/themes/simple/src/less/style.less deleted file mode 100644 index 7dca47402..000000000 --- a/searx/static/themes/simple/src/less/style.less +++ /dev/null @@ -1,1162 +0,0 @@ -/* -* SearXNG, A privacy-respecting, hackable metasearch engine -* -* To convert "style.less" to "style.css" run: $make styles -*/ - -// stylelint-disable no-descending-specificity - -@import (inline) "../../node_modules/normalize.css/normalize.css"; -@import "definitions.less"; -@import "mixins.less"; -@import "code.less"; -@import "toolkit.less"; -@import "autocomplete.less"; -@import "detail.less"; -@import "animations.less"; -@import "embedded.less"; -@import "info.less"; -@import "new_issue.less"; -@import "stats.less"; -@import "result_templates.less"; - -// for index.html template -@import "index.less"; - -// for preferences.html template -@import "preferences.less"; - -// Search-Field -@import "search.less"; - -// to center the results -@import "style-center.less"; - -// ion-icon -.ion-icon { - display: inline-block; - vertical-align: bottom; - line-height: 1; - text-decoration: inherit; - .ltr-transform(); -} - -.ion-icon-small { - width: 1rem; - height: 1rem; - .ion-icon; -} - -.ion-icon-big { - width: 1.5rem; - height: 1.5rem; - .ion-icon; -} - -// Main LESS-Code -html { - font-family: sans-serif; - font-size: 0.9em; - .text-size-adjust; - - color: var(--color-base-font); - background-color: var(--color-base-background); - padding: 0; - margin: 0; - - scroll-behavior: smooth; -} - -body, -main { - padding: 0; - margin: 0; -} - -body { - display: flex; - flex-direction: column; - height: 100vh; - margin: 0; -} - -main { - width: 100%; - margin-bottom: 2rem; - flex: 1; -} - -.page_with_header { - margin: 2em auto; - width: 85em; -} - -footer { - clear: both; - min-height: 4rem; - padding: 1rem 0; - width: 100%; - text-align: center; - background-color: var(--color-footer-background); - border-top: 1px solid var(--color-footer-border); - overflow: hidden; - - p { - font-size: 0.9em; - } -} - -.page_with_header .logo { - height: 40px; -} - -input[type="submit"], -#results button[type="submit"], -.button { - padding: 0.7rem; - display: inline-block; - background: var(--color-btn-background); - color: var(--color-btn-font); - .rounded-corners; - - border: 0; - cursor: pointer; -} - -a { - text-decoration: none; - color: var(--color-url-font); - - &:visited { - color: var(--color-url-visited-font); - - .highlight { - color: var(--color-url-visited-font); - } - } -} - -article[data-vim-selected] { - background: var(--color-result-vim-selected); - .ltr-border-left(0.2rem solid var(--color-result-vim-arrow)); - .ltr-rounded-right-corners(10px); -} - -article.result-images[data-vim-selected] { - background: var(--color-result-vim-arrow); - border: none; - .rounded-corners; - - .image_thumbnail { - filter: opacity(60%); - } - - span.title, - span.source { - color: var(--color-result-image-span-font-selected); - } -} - -article[data-vim-selected].category-videos, -article[data-vim-selected].category-news, -article[data-vim-selected].category-map, -article[data-vim-selected].category-music, -article[data-vim-selected].category-files, -article[data-vim-selected].category-social { - border: 1px solid var(--color-result-vim-arrow); - .rounded-corners; -} - -.result { - margin: @results-margin 0; - padding: @result-padding; - box-sizing: border-box; - width: 100%; - .ltr-border-left(0.2rem solid transparent); - - h3 { - font-size: 1.2rem; - word-wrap: break-word; - margin: 0.4rem 0 0.4rem 0; - padding: 0; - - a { - color: var(--color-result-link-font); - font-weight: normal; - font-size: 1.1em; - - &:visited { - color: var(--color-result-link-visited-font); - } - - &:focus, - &:hover { - text-decoration: underline; - border: none; - outline: none; - } - } - } - - .cache_link, - .proxyfied_link { - font-size: smaller !important; - margin-left: 0.5rem; - } - - .content, - .stat { - font-size: 0.9em; - margin: 0; - padding: 0; - max-width: 54em; - word-wrap: break-word; - line-height: 1.24; - - .highlight { - color: var(--color-result-description-highlight-font); - background: inherit; - font-weight: bold; - } - } - - .altlink a { - font-size: 0.9em; - margin: 0 10px 0 0; - .show-content-button; - } - - .codelines { - .highlight { - color: inherit; - background: inherit; - font-weight: normal; - } - } - - .url_header { - display: flex; - gap: 0.5rem; - } - - .url_wrapper { - display: flex; - align-items: center; - font-size: 1rem; - color: var(--color-result-url-font); - flex-flow: row nowrap; - overflow: hidden; - margin: 0; - padding: 0; - - .url_o1 { - white-space: nowrap; - flex-shrink: 1; - padding-bottom: 1px; - - .url_i1 { - unicode-bidi: plaintext; - } - } - - .url_o1::after { - content: " "; - width: 1ch; - display: inline-block; - } - - .url_o2 { - overflow: hidden; - white-space: nowrap; - flex: 0 1 content; - text-align: right; - padding-bottom: 1px; - - .url_i2 { - float: right; - } - } - } - - .published_date, - .result_length, - .result_views, - .result_author, - .result_shipping, - .result_source_country { - font-size: 0.8em; - color: var(--color-result-publishdate-font); - } - - .result_price { - font-size: 1.2em; - color: var(--color-result-description-highlight-font); - } - - img.thumbnail { - .ltr-float-left(); - padding-top: 0.6rem; - .ltr-padding-right(1rem); - width: 7rem; - height: unset; // remove height value that was needed for lazy loading - } - - .break { - clear: both; - } -} - -.result-paper, -.result-packages { - .attributes { - display: table; - border-spacing: 0.125rem; - - div { - display: table-row; - - span { - font-size: 0.9rem; - margin-top: 0.25rem; - display: table-cell; - - time { - font-size: 0.9rem; - } - } - - span:first-child { - color: var(--color-base-font); - min-width: 10rem; - } - - span:nth-child(2) { - color: var(--color-result-publishdate-font); - } - } - } - - .content { - margin-top: 0.25rem; - } - - .comments { - font-size: 0.9rem; - margin: 0.25rem 0 0 0; - padding: 0; - word-wrap: break-word; - line-height: 1.24; - font-style: italic; - } -} - -.result-packages { - .attributes { - margin-top: 0.3rem; - } -} - -.template_group_images { - display: flex; - flex-wrap: wrap; -} - -.template_group_images::after { - flex-grow: 10; - content: ""; -} - -.category-videos, -.category-news, -.category-map, -.category-music, -.category-files, -.category-social { - border: 1px solid var(--color-result-border); - margin: 0 @results-tablet-offset 1rem @results-tablet-offset !important; - .rounded-corners; -} - -.category-social .image { - width: auto !important; - min-width: 48px; - min-height: 48px; - padding: 0 5px 25px 0 !important; -} - -.audio-control audio { - width: 100%; - padding: 10px 0 0 0; -} - -.embedded-content iframe { - width: 100%; - padding: 10px 0 0 0; -} - -.result-videos { - img.thumbnail { - .ltr-float-left(); - padding-top: 0.6rem; - .ltr-padding-right(1rem); - width: 20rem; - height: unset; // remove height value that was needed for lazy loading - } -} - -.result-videos .content { - overflow: hidden; -} - -.result-videos .embedded-video iframe { - width: 100%; - aspect-ratio: 16 / 9; - padding: 10px 0 0 0; -} - -@supports not (aspect-ratio: 1 / 1) { - // support older browsers which do not have aspect-ratio - // https://caniuse.com/?search=aspect-ratio - .result-videos .embedded-video iframe { - height: calc(@results-width * 9 / 16); - } -} - -.engines { - .ltr-float-right(); - display: flex; - flex-wrap: wrap; - justify-content: flex-end; - color: var(--color-result-engines-font); - - span { - font-size: smaller; - margin-top: 0; - margin-bottom: 0; - .ltr-margin-right(0.5rem); - .ltr-margin-left(0); - } -} - -.small_font { - font-size: 0.8em; -} - -.highlight { - color: var(--color-result-link-font-highlight); - background: inherit; -} - -.empty_element { - font-style: italic; -} - -.result-images { - flex-grow: 1; - padding: 0.5rem 0.5rem 3rem 0.5rem; - margin: 0.25rem; - border: none !important; - height: @results-image-row-height; - width: unset; - - & > a { - position: relative; - outline: none; - } - - img { - margin: 0; - padding: 0; - border: none; - height: 100%; - width: 100%; - object-fit: cover; - vertical-align: bottom; - background: var(--color-result-image-background); - } - - .image_resolution { - position: absolute; - right: 0; - bottom: 0; - background: var(--color-image-resolution-background); - padding: 0.3rem 0.5rem; - font-size: 0.9rem; - color: var(--color-image-resolution-font); - border-top-left-radius: 0.3rem; - } - - span.title, - span.source { - display: block; - position: absolute; - - width: 100%; - font-size: 0.9rem; - color: var(--color-result-image-span-font); - padding: 0.5rem 0 0 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - span.source { - padding: 1.8rem 0 0 0; - font-size: 0.7rem; - } -} - -.result-map { - img.image { - .ltr-float-right() !important; - height: 100px !important; - width: auto !important; - } - - table { - font-size: 0.9em; - width: auto; - border-collapse: separate; - border-spacing: 0 0.35rem; - - th { - font-weight: inherit; - width: 17rem; - vertical-align: top; - .ltr-text-align-left(); - } - - td { - vertical-align: top; - .ltr-text-align-left(); - } - } -} - -.hidden { - display: none !important; -} - -#results { - margin-top: 1rem; - .ltr-margin-right(2rem); - margin-bottom: 0; - .ltr-margin-left(@results-offset); - display: grid; - grid-template: - "corrections sidebar" min-content - "answers sidebar" min-content - "urls sidebar" 1fr - "pagination sidebar" min-content - / @results-width @results-sidebar-width - ; - gap: 0 @results-gap; -} - -#results #sidebar *:first-child { - margin-top: 0; -} - -#urls { - padding: 0; - grid-area: urls; -} - -#apis .wrapper { - display: flex; -} - -#suggestions { - .wrapper { - display: flex; - flex-flow: column; - justify-content: flex-end; - - form { - display: inline-block; - flex: 1 1 50%; - } - } -} - -#suggestions, -#infoboxes { - input { - padding: 0; - margin: 3px; - font-size: 0.9em; - display: inline-block; - background: transparent; - color: var(--color-result-search-url-font); - cursor: pointer; - width: calc(100%); - text-overflow: ellipsis; - overflow: hidden; - text-align: left; - } - - input[type="submit"], - .infobox .url a { - color: var(--color-result-link-font); - text-decoration: none; - font-size: 0.9rem; - - &:hover { - text-decoration: underline; - } - } -} - -#corrections { - grid-area: corrections; - display: flex; - flex-flow: row wrap; - margin: 0 0 1em 0; - - h4, - input[type="submit"] { - display: inline-block; - padding: 0.5rem; - margin: 0.5rem; - } - - input[type="submit"] { - font-size: 0.8rem; - .rounded-corners-tiny; - } -} - -#infoboxes .title, -#suggestions .title, -#search_url .title, -#engines_msg .title, -#apis .title { - margin: 2em 0 0.5em 0; - color: var(--color-base-font); -} - -summary.title { - cursor: pointer; - padding-top: 1em; -} - -.sidebar-collapsible { - border-top: 1px solid var(--color-sidebar-border); - padding-bottom: 0.5em; -} - -#sidebar-end-collapsible { - border-bottom: 1px solid var(--color-sidebar-border); - width: 100%; -} - -#answers { - grid-area: answers; - background: var(--color-answer-background); - padding: @result-padding; - margin: 1rem 0; - margin-top: 0; - color: var(--color-answer-font); - .rounded-corners; - - h4 { - display: none; - } - - span { - overflow-wrap: anywhere; - } - - .answer { - display: flex; - flex-direction: column; - } - - .answer-url { - margin: 5px 10px 10px auto; - } -} - -#infoboxes { - form { - min-width: 210px; - } -} - -#sidebar { - grid-area: sidebar; - word-wrap: break-word; - color: var(--color-sidebar-font); - - .infobox { - margin: 10px 0 10px; - border: 1px solid var(--color-sidebar-border); - padding: 1rem; - font-size: 0.9em; - .rounded-corners; - - h2 { - margin: 0 0 0.5em 0; - } - - img { - max-width: 100%; - max-height: 12em; - display: block; - margin: 0 auto; - padding: 0; - } - - dt { - font-weight: bold; - } - - .attributes { - dl { - margin: 0.5em 0; - } - - dt { - display: inline; - margin-top: 0.5em; - .ltr-margin-right(0.25em); - margin-bottom: 0.5em; - .ltr-margin-left(0); - padding: 0; - } - - dd { - display: inline; - margin: 0.5em 0; - padding: 0; - } - } - - input { - font-size: 1em; - } - - br { - clear: both; - } - - .attributes, - .urls { - clear: both; - } - } -} - -#apis { - input { - font-size: 0.9em; - margin: 0 10px 0 0; - .show-content-button; - } -} - -#engines_msg { - .engine-name { - width: 10rem; - } - - .response-error { - color: var(--color-error); - } - - .bar-chart-value { - width: auto; - } -} - -#search_url { - div.selectable_url { - pre { - float: left; - width: 200em; - } - } - - button#copy_url { - float: right; - padding: 0.4rem; - margin-left: 0.5rem; - border-radius: 0.3rem; - display: none; // will be shown by JS. - } -} - -#links_on_top { - position: absolute; - .ltr-right(1rem); - .ltr-text-align-right(); - top: 2.7rem; - padding: 0; - border: 0; - display: flex; - align-items: center; - font-size: 1em; - color: var(--color-search-font); - - a { - display: flex; - align-items: center; - margin-left: 1em; - - svg { - font-size: 1.2em; - .ltr-margin-right(0.125em); - } - } - - a, - a:link *, - a:hover *, - a:visited *, - a:active * { - color: var(--color-search-font); - } -} - -#pagination { - grid-area: pagination; - - br { - clear: both; - } -} - -.numbered_pagination { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - overflow: hidden; -} - -.page_number { - background: transparent !important; - color: var(--color-result-link-font) !important; - text-decoration: underline; -} - -.page_number_current { - background: transparent; - color: var(--color-result-link-visited-font); - border: none; -} - -#backToTop { - border: 1px solid var(--color-backtotop-border); - margin: 0; - padding: 0; - font-size: 1em; - background: var(--color-backtotop-background); - position: fixed; - bottom: 8rem; - .ltr-left(@results-width + @results-offset + (0.5 * @results-gap - 1.2em)); - transition: opacity 0.5s; - opacity: 0; - pointer-events: none; - .rounded-corners; - - a { - display: block; - margin: 0; - padding: 0.7em; - } - - a, - a:visited, - a:hover, - a:active { - color: var(--color-backtotop-font); - } -} - -#results.scrolling #backToTop { - opacity: 1; - pointer-events: all; -} - -/* - tablet layout -*/ - -.results-tablet() { - #links_on_top { - span { - display: none; - } - } - - .page_with_header { - margin: 2rem 0.5rem; - width: auto; - } - - #infoboxes { - position: inherit; - max-width: inherit; - - .infobox { - clear: both; - - img { - .ltr-float-left(); - max-width: 10em; - margin-top: 0.5em; - .ltr-margin-right(0.5em); - margin-bottom: 0.5em; - .ltr-margin-left(0); - } - } - } - - #sidebar { - margin: 0 @results-tablet-offset @results-margin @results-tablet-offset; - padding: 0; - float: none; - border: none; - width: auto; - - input { - border: 0; - } - } - - .result { - .thumbnail { - max-width: 98%; - } - - .url { - span.url { - display: block; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - width: 100%; - } - } - - .engines { - .ltr-float-right(); - display: flex; - flex-wrap: wrap; - justify-content: flex-end; - padding: 3px 0 0 0; - } - } - - .result-images { - border-bottom: none !important; - } - - .image_result { - max-width: 98%; - - img { - max-width: 98%; - } - } - - #backToTop { - display: none; - } - - #pagination { - margin: 2rem 0 0 0 !important; - } - - #main_results div#results { - margin: 0 auto; - justify-content: center; - display: grid; - grid-template: - "corrections" min-content - "answers" min-content - "sidebar" min-content - "urls" 1fr - "pagination" min-content - / @results-width - ; - gap: 0; - } -} - -@media screen and (width <= calc(@tablet - 0.5px)) { - #links_on_top { - span { - display: none; - } - } -} - -@media screen and (width <= 52rem) { - body.results_endpoint { - #links_on_top { - .link_on_top_about, - .link_on_top_donate { - display: none; - } - } - } -} - -@media screen and (min-width: @phone) and (max-width: @tablet) { - // when .center-alignment-yes, see style-center.less - // the media query includes "min-width: @phone" - // because the phone layout includes the tablet layout unconditionally. - .center-alignment-no { - .results-tablet(); - } -} - -/* Misc */ - -#main_results div#results.only_template_images { - margin: 1rem @results-tablet-offset 0 @results-tablet-offset; - display: grid; - grid-template: - "corrections" min-content - "answers" min-content - "sidebar" min-content - "urls" 1fr - "pagination" min-content - / 100%; - gap: 0; - - #sidebar { - display: none; - } - - #urls { - margin: 0; - display: flex; - flex-wrap: wrap; - } - - #urls::after { - flex-grow: 10; - content: ""; - } - - #backToTop { - .ltr-left(auto); - .ltr-right(1rem); - } - - #pagination { - .ltr-margin-right(4rem); - } -} - -/* - phone layout -*/ - -@media screen and (max-width: @phone) { - // based on the tablet layout - .results-tablet(); - - html { - background-color: var(--color-base-background-mobile); - } - - #main_results div#results { - grid-template-columns: 100%; - margin: 0 auto; - } - - #links_on_top { - top: 1.4rem; - .ltr-right(10px); - } - - #main_index #links_on_top { - top: 0.5rem; - .ltr-right(0.5rem); - } - - #results { - margin: 0; - padding: 0; - } - - #pagination { - margin: 2rem 1rem 0 1rem !important; - } - - article[data-vim-selected] { - border: 1px solid var(--color-result-vim-arrow); - .rounded-corners; - } - - .result { - background: var(--color-result-background); - border: 1px solid var(--color-result-background); - margin: 1rem 2%; - width: 96%; - .rounded-corners; - } - - .result-images { - margin: 0; - height: @results-image-row-height-phone; - background: var(--color-base-background-mobile); - width: unset; - } - - .infobox { - border: none !important; - background-color: var(--color-sidebar-background); - } - - .numbered_pagination { - display: none; - } - - .result-paper, - .result-packages { - .attributes { - display: block; - - div { - display: block; - - span { - display: inline; - } - - span:first-child { - font-weight: bold; - } - - span:nth-child(2) { - .ltr-margin-left(0.5rem); - } - } - } - } -} - -/* - small-phone layout -*/ - -@media screen and (max-width: @small-phone) { - .result-videos { - img.thumbnail { - float: none !important; - } - - .content { - overflow: inherit; - } - } -} - -pre code { - white-space: pre-wrap; -} diff --git a/searx/static/themes/simple/src/less/toolkit.less b/searx/static/themes/simple/src/less/toolkit.less deleted file mode 100644 index d3fb2273b..000000000 --- a/searx/static/themes/simple/src/less/toolkit.less +++ /dev/null @@ -1,646 +0,0 @@ -// other solution : http://stackoverflow.com/questions/1577598/how-to-hide-parts-of-html-when-javascript-is-disabled/13857783#13857783 - -// stylelint-disable no-descending-specificity - -html.no-js .hide_if_nojs { - display: none; -} - -html.js .show_if_nojs { - display: none; -} - -.center { - text-align: center; -} - -.right { - float: right; -} - -.left { - float: left; -} - -.invisible { - display: none !important; -} - -.list-unstyled { - list-style-type: none; - - li { - margin-top: 4px; - margin-bottom: 4px; - } -} - -.danger { - background-color: var(--color-error-background); -} - -.warning { - background: var(--color-warning-background); -} - -.success { - background: var(--color-success-background); -} - -.badge { - display: inline-block; - color: var(--color-toolkit-badge-font); - background-color: var(--color-toolkit-badge-background); - text-align: center; - white-space: nowrap; - vertical-align: baseline; - min-width: 10px; - padding: 1px 5px; - border-radius: 5px; -} - -// kbd -kbd { - padding: 2px 4px; - margin: 1px; - font-size: 90%; - color: var(--color-toolkit-kbd-font); - background: var(--color-toolkit-kbd-background); -} - -// table -table { - width: 100%; - - &.striped { - tr { - border-bottom: 1px solid var(--color-settings-tr-hover); - } - } -} - -th { - padding: 0.4em; -} - -td { - padding: 0 4px; -} - -tr { - &:hover { - background: var(--color-settings-tr-hover) !important; - } -} - -// pre -.pre() { - display: block; - font-size: 0.8em; - word-break: break-all; - margin: 0.1em; - user-select: all; -} - -div.selectable_url { - display: block; - border: 1px solid var(--color-result-search-url-border); - padding: 4px; - color: var(--color-result-search-url-font); - margin: 0.1em; - overflow: hidden; - height: 1.2em; - line-height: 1.2em; - .rounded-corners-tiny; - - pre { - .pre(); - } -} - -// dialog -.dialog() { - position: relative; - display: flex; - padding: 1rem; - margin: 0 0 1em 0; - border: 1px solid var(--color-toolkit-dialog-border); - .ltr-text-align-left(); - .rounded-corners; - - .close { - .ltr-float-right(); - position: relative; - top: -3px; - color: inherit; - font-size: 1.5em; - } - - ul, - ol, - p { - margin: 1px 0 0 0; - } - - table { - width: auto; - } - - tr { - vertical-align: text-top; - - &:hover { - background: transparent !important; - } - } - - td { - padding: 0 1em 0 0; - padding-top: 0; - .ltr-padding-right(1rem); - padding-bottom: 0; - .ltr-padding-left(0); - } - - h4 { - margin-top: 0.3em; - margin-bottom: 0.3em; - } -} - -.dialog-error { - .dialog(); - - color: var(--color-error); - background: var(--color-error-background); - border-color: var(--color-error); -} - -.dialog-error-block { - .dialog(); - - display: block; - color: var(--color-error); - background: var(--color-error-background); - border-color: var(--color-error); -} - -.dialog-warning { - .dialog(); - - color: var(--color-warning); - background: var(--color-warning-background); - border-color: var(--color-warning); -} - -.dialog-modal { - .dialog(); - - display: block; - background: var(--color-toolkit-dialog-background); - position: fixed; - top: 50%; - left: 50%; - margin: 0 auto; - transform: translate(-50%, -50%); - z-index: 5000; - - h3 { - margin-top: 0; - } -} - -// btn-collapse -.btn-collapse { - cursor: pointer; -} - -// -.scrollx { - overflow: auto hidden; - display: block; - padding: 0; - margin: 0; - border: none; -} - -/* -- tabs -- */ -.tabs .tabs > label { - font-size: 90%; -} - -ul.tabs { - border-bottom: 1px solid var(--color-toolkit-tabs-section-border); - list-style: none; - padding-left: 0; - - li { - display: flex; - } -} - -.tabs { - display: flex; - flex-wrap: wrap; - width: 100%; - min-width: 100%; - - & > * { - order: 2; - } - - & > input[type=radio] { - display: none; - } - - & > label, - & > li > a { - order: 1; - padding: 0.7em; - margin: 0 0.7em; - letter-spacing: 0.5px; - text-transform: uppercase; - border: solid var(--color-toolkit-tabs-label-border); - border-width: 0 0 2px 0; - color: unset; - - .disable-user-select(); - - cursor: pointer; - - &.active { - border-bottom: 2px solid var(--color-categories-item-border-selected); - background: var(--color-categories-item-selected); - color: var(--color-categories-item-selected-font); - } - } - - & > label:hover, - & > li > a:hover { - border-bottom: 2px solid var(--color-categories-item-border-selected); - } - - & > section { - min-width: 100%; - padding: 0.7rem 0; - box-sizing: border-box; - border-top: 1px solid var(--color-toolkit-tabs-section-border); - display: none; - } - - // default selection - & > label:last-of-type { - border-bottom: 2px solid var(--color-categories-item-border-selected); - background: var(--color-categories-item-selected); - color: var(--color-categories-item-selected-font); - letter-spacing: -0.1px; - } - - & > section:last-of-type { - display: block; - } -} - -html body .tabs > input:checked { - ~ section { - display: none; - } - - ~ label { - position: inherited; - background: inherit; - border-bottom: 2px solid transparent; - font-weight: normal; - color: inherit; - - &:hover { - border-bottom: 2px solid var(--color-categories-item-border-selected); - } - } - - + label { - border-bottom: 2px solid var(--color-categories-item-border-selected); - background: var(--color-categories-item-selected); - color: var(--color-categories-item-selected-font); - } - - + label + section { - display: block; - } -} - -/* -- select -- */ -select { - height: 2.4rem; - margin-top: 0; - .ltr-margin-right(1rem); - margin-bottom: 0; - .ltr-margin-left(0); - padding: 0.2rem !important; - color: var(--color-search-font); - font-size: 0.9rem; - z-index: 100; - - &:hover, - &:focus { - cursor: pointer; - } -} - -@supports ((background-position-x: 100%) and ((appearance: none) or (-webkit-appearance: none) or (-moz-appearance: none))) { - select { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - border-width: 0 2rem 0 0; - border-color: transparent; - background: data-uri('image/svg+xml;charset=UTF-8', @select-light-svg-path) no-repeat; - background-position-x: calc(100% + 2rem); - background-size: 2rem; - background-origin: content-box; - background-color: var(--color-toolkit-select-background); - outline: medium none; - text-overflow: ellipsis; - .rounded-corners-tiny; - - &:hover, - &:focus { - background-color: var(--color-toolkit-select-background-hover); - } - - option { - background-color: var(--color-base-background); - } - } - - @media (prefers-color-scheme: dark) { - html.theme-auto select, - html.theme-dark select { - background-image: data-uri('image/svg+xml;charset=UTF-8', @select-dark-svg-path); - } - } - - html.theme-dark select { - background-image: data-uri('image/svg+xml;charset=UTF-8', @select-dark-svg-path); - } -} - -/* -- checkbox-onoff -- */ -input.checkbox-onoff[type="checkbox"] { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - cursor: pointer; - display: inline-block; - width: 2.5em; - height: 0.7em; - box-shadow: none !important; - margin: 0 16px; - border-radius: 10px; - position: relative; - - /* focus & hover */ - &:focus, - &:hover { - outline: none; - } - - &:focus::after { - content: ""; - position: absolute; - width: 3.5em; - height: 1.65em; - border: 1px solid var(--color-btn-background); - border-radius: 12px; - box-shadow: var(--color-btn-background) 0 0 3px; - z-index: 1200; - top: -0.55em; - left: -0.6em; - } - - &::before { - position: absolute; - top: -0.5em; - display: flex; - justify-content: center; - align-items: center; - font-size: 0.75em; - width: 1.875em; - height: 1.875em; - border-radius: 50%; - } -} - -/* check mark -reversed-checkbox displays unchecked checkedboxes as checked, and vice versa. -see https://github.com/searxng/searxng/blob/3408d061aab9abc6168fec9bbc6deab71b236dac/searx/templates/simple/preferences.html#L313 -*/ -input.checkbox-onoff[type="checkbox"], -input.checkbox-onoff.reversed-checkbox[type="checkbox"]:checked { - background: var(--color-toolkit-checkbox-onoff-off-background); - - &::before { - left: -0.5em; - content: "\2715"; - color: var(--color-toolkit-checkbox-onoff-off-mark-color); - background: var(--color-toolkit-checkbox-onoff-off-mark-background); - } -} - -input.checkbox-onoff[type="checkbox"]:checked, -input.checkbox-onoff.reversed-checkbox[type="checkbox"] { - background: var(--color-toolkit-checkbox-onoff-on-background); - - &::before { - left: calc(100% - 1.5em); - content: "\2713"; - color: var(--color-toolkit-checkbox-onoff-on-mark-color); - background: var(--color-toolkit-checkbox-onoff-on-mark-background); - } -} - -/* -- checkbox -- */ -@supports (transform: rotate(-45deg)) { - input[type=checkbox]:not(.checkbox-onoff) { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - - width: 20px; - height: 20px; - cursor: pointer; - position: relative; - top: 0; - left: 0; - border: 2px solid var(--color-toolkit-checkbox-input-border); - .rounded-corners(0.3em); - - &::after { - content: ''; - width: 9px; - height: 5px; - position: absolute; - top: 3px; - left: 2px; - border: 3px solid var(--color-toolkit-checkbox-label-border); - border-top: none; - border-right: none; - background: transparent; - opacity: 0; - transform: rotate(-45deg); - } - - &:checked::after { - border-color: var(--color-toolkit-checkbox-input-border); - opacity: 1; - } - } - - // disabled : can't be focused, show only the check mark - input[type=checkbox][disabled]:not(.checkbox-onoff) { - border: inherit; - background-color: transparent !important; - cursor: inherit; - } - - // if not checked and possible to checked then display a "light" check mark on hover - input.checkbox[type=checkbox]:not(:checked, [disabled], .checkbox-onoff):hover::after { - opacity: 0.5; - } -} - -@media screen and (max-width: @phone) { - .tabs > label { - width: 100%; - } -} - -/* -- loader -- */ -.loader, -.loader::after { - border-radius: 50%; - width: 2em; - height: 2em; -} - -.loader { - margin: 1em auto; - font-size: 10px; - position: relative; - text-indent: -9999em; - border-top: 0.5em solid var(--color-toolkit-loader-border); - border-right: 0.5em solid var(--color-toolkit-loader-border); - border-bottom: 0.5em solid var(--color-toolkit-loader-border); - border-left: 0.5em solid var(--color-toolkit-loader-borderleft); - -webkit-transform: translateZ(0); - -ms-transform: translateZ(0); - transform: translateZ(0); - -webkit-animation: load8 1.2s infinite linear; - animation: load8 1.2s infinite linear; -} - -@-webkit-keyframes load8 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } -} - -@keyframes load8 { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } -} - -/* -- engine-tooltip -- */ -.engine-tooltip { - display: none; - position: absolute; - padding: 0.5rem 1rem; - margin: 0 0 0 2rem; - border: 1px solid var(--color-toolkit-engine-tooltip-border); - background: var(--color-toolkit-engine-tooltip-background); - font-size: 14px; - font-weight: normal; - z-index: 5000; - text-align: left; - .rounded-corners; -} - -th:hover .engine-tooltip, -td:hover .engine-tooltip, -.engine-tooltip:hover { - display: inline-block; -} - -/* -- stacked bar chart -- */ -.stacked-bar-chart { - margin: 0; - padding: 0 0.125rem 0 4rem; - width: 100%; - width: -moz-available; - width: -webkit-fill-available; - width: fill; - flex-flow: row nowrap; - align-items: center; - display: inline-flex; -} - -.stacked-bar-chart-value { - width: 3rem; - display: inline-block; - position: absolute; - padding: 0 0.5rem; - text-align: right; -} - -.stacked-bar-chart-base { - display: flex; - flex-shrink: 0; - flex-grow: 0; - flex-basis: unset; -} - -.stacked-bar-chart-median { - .stacked-bar-chart-base(); - - background: var(--color-base-font); - border: 1px solid rgba(var(--color-base-font-rgb), 0.9); - padding: 0.3rem 0; -} - -.stacked-bar-chart-rate80 { - .stacked-bar-chart-base(); - - background: transparent; - border: 1px solid rgba(var(--color-base-font-rgb), 0.3); - padding: 0.3rem 0; -} - -.stacked-bar-chart-rate95 { - .stacked-bar-chart-base(); - - background: transparent; - border-bottom: 1px dotted rgba(var(--color-base-font-rgb), 0.5); - padding: 0; -} - -.stacked-bar-chart-rate100 { - .stacked-bar-chart-base(); - - background: transparent; - border-left: 1px solid rgba(var(--color-base-font-rgb), 0.9); - padding: 0.4rem 0; - width: 1px; -} diff --git a/searx/static/themes/simple/src/less/toolkit_loader.less b/searx/static/themes/simple/src/less/toolkit_loader.less deleted file mode 100644 index 8b705e42b..000000000 --- a/searx/static/themes/simple/src/less/toolkit_loader.less +++ /dev/null @@ -1,29 +0,0 @@ -.loader, -.loader::after { - border-radius: 50%; - width: 10em; - height: 10em; -} - -.loader { - margin: 60px auto; - font-size: 10px; - position: relative; - text-indent: -9999em; - border-top: 1.1em solid var(--color-loading-indicator); - border-right: 1.1em solid var(--color-loading-indicator); - border-bottom: 1.1em solid var(--color-loading-indicator); - border-left: 1.1em solid var(--color-loading-indicator-gap); - transform: translateZ(0); - animation: load8 1.1s infinite linear; -} - -@keyframes load8 { - 0% { - transform: rotate(0deg); - } - - 100% { - transform: rotate(360deg); - } -} diff --git a/searx/static/themes/simple/src/svg/information-circle-outline.svg b/searx/static/themes/simple/src/svg/information-circle-outline.svg deleted file mode 100644 index b7c300094..000000000 --- a/searx/static/themes/simple/src/svg/information-circle-outline.svg +++ /dev/null @@ -1,6 +0,0 @@ - - Information Circle - - - - \ No newline at end of file diff --git a/searx/static/themes/simple/src/svg/select-dark.svg b/searx/static/themes/simple/src/svg/select-dark.svg deleted file mode 100644 index 97335cea5..000000000 --- a/searx/static/themes/simple/src/svg/select-dark.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/searx/static/themes/simple/src/svg/select-light.svg b/searx/static/themes/simple/src/svg/select-light.svg deleted file mode 100644 index 3b707f018..000000000 --- a/searx/static/themes/simple/src/svg/select-light.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file -- cgit v1.2.3