From 62a9b9e9492c45c7288c1be22f6d7ddb332ab80f Mon Sep 17 00:00:00 2001 From: Ben Busby Date: Sat, 20 Mar 2021 21:21:41 -0400 Subject: [PATCH] Allow user-defined CSS/theming (#227) * Add custom CSS field to config This allows users to set/customize an instance's theme and appearance to their liking. The config CSS field is prepopulated with all default CSS variable values to allow quick editing. Note that this can be somewhat of a "footgun" if someone updates the CSS to hide all fields/search/etc. Should probably add some sort of bandaid "admin" feature for public instances to employ until the whole cookie/session issue is investigated further. * Symlink all app static files to test dir * Refactor app/misc/*.json -> app/static/settings/*.json The country/language json files are used for user config settings, so the "misc" name didn't really make sense. Also moved these to the static folder to make testing easier. * Fix light theme variables in dark theme css * Minor style tweaking --- app/__init__.py | 8 +- app/models/config.py | 7 + app/routes.py | 4 +- app/static/css/dark-theme.css | 111 +++++++++++++--- app/static/css/light-theme.css | 130 +++++++++++++++++++ app/static/css/main.css | 73 +++++++---- app/static/css/search-dark.css | 40 ------ app/static/css/search.css | 39 ------ app/static/css/variables.css | 24 ++++ app/static/img/whoogle.svg | 1 + app/static/js/controller.js | 40 ------ app/{misc => static/settings}/countries.json | 0 app/{misc => static/settings}/languages.json | 0 app/templates/display.html | 9 +- app/templates/header.html | 16 +-- app/templates/index.html | 85 +++++++----- run | 6 +- test/misc | 1 - 18 files changed, 381 insertions(+), 213 deletions(-) create mode 100644 app/static/css/light-theme.css delete mode 100644 app/static/css/search-dark.css delete mode 100644 app/static/css/search.css create mode 100644 app/static/css/variables.css create mode 100644 app/static/img/whoogle.svg rename app/{misc => static/settings}/countries.json (100%) rename app/{misc => static/settings}/languages.json (100%) delete mode 120000 test/misc diff --git a/app/__init__.py b/app/__init__.py index e0cf88e..6ce52b0 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -18,13 +18,13 @@ app.config['VERSION_NUMBER'] = '0.3.2' app.config['APP_ROOT'] = os.getenv( 'APP_ROOT', os.path.dirname(os.path.abspath(__file__))) -app.config['LANGUAGES'] = json.load(open( - os.path.join(app.config['APP_ROOT'], 'misc/languages.json'))) -app.config['COUNTRIES'] = json.load(open( - os.path.join(app.config['APP_ROOT'], 'misc/countries.json'))) app.config['STATIC_FOLDER'] = os.getenv( 'STATIC_FOLDER', os.path.join(app.config['APP_ROOT'], 'static')) +app.config['LANGUAGES'] = json.load(open( + os.path.join(app.config['STATIC_FOLDER'], 'settings/languages.json'))) +app.config['COUNTRIES'] = json.load(open( + os.path.join(app.config['STATIC_FOLDER'], 'settings/countries.json'))) app.config['CONFIG_PATH'] = os.getenv( 'CONFIG_VOLUME', os.path.join(app.config['STATIC_FOLDER'], 'config')) diff --git a/app/models/config.py b/app/models/config.py index 3916be2..756af29 100644 --- a/app/models/config.py +++ b/app/models/config.py @@ -1,8 +1,15 @@ +from flask import current_app +import os + + class Config: def __init__(self, **kwargs): + app_config = current_app.config self.url = '' self.lang_search = '' self.lang_interface = '' + self.style = open(os.path.join(app_config['STATIC_FOLDER'], + 'css/variables.css')).read() self.ctry = '' self.safe = False self.dark = False diff --git a/app/routes.py b/app/routes.py index b084f71..10336ed 100644 --- a/app/routes.py +++ b/app/routes.py @@ -233,12 +233,12 @@ def search(): 'display.html', query=urlparse.unquote(query), search_type=search_util.search_type, - dark_mode=g.user_config.dark, + config=g.user_config, response=response, version_number=app.config['VERSION_NUMBER'], search_header=(render_template( 'header.html', - dark_mode=g.user_config.dark, + config=g.user_config, query=urlparse.unquote(query), search_type=search_util.search_type, mobile=g.user_request.mobile) diff --git a/app/static/css/dark-theme.css b/app/static/css/dark-theme.css index 4bd6af1..940f646 100644 --- a/app/static/css/dark-theme.css +++ b/app/static/css/dark-theme.css @@ -1,13 +1,17 @@ html { - background-color: #222 !important; + background: var(--whoogle-dark-background) !important; } body { - background-color: #222 !important; + background: var(--whoogle-dark-background) !important; } div { - color: #fff !important; + color: var(--whoogle-dark-text) !important; +} + +label { + color: var(--whoogle-dark-contrast-text) !important; } li a { @@ -15,43 +19,114 @@ li a { } li { - color: #fff !important; + color: var(--whoogle-dark-text) !important; +} + +textarea { + background: var(--whoogle-dark-background) !important; + color: var(--whoogle-dark-text) !important; } a:visited h3 div { - color: #bbbbff !important; + color: var(--whoogle-dark-result-visited) !important; } a:link h3 div { - color: #4b8eea !important; + color: var(--whoogle-dark-result-title) !important; } a:link div { - color: #aaffaa !important; + color: var(--whoogle-dark-result-url) !important; } div span { - color: #bbb !important; + color: var(--whoogle-dark-secondary-text) !important; } input { - background-color: #111 !important; - color: #fff !important; + background-color: var(--whoogle-dark-background) !important; + color: var(--whoogle-dark-text) !important; } -#search-bar { - color: #fff !important; - background-color: #222 !important; +select { + background: var(--whoogle-dark-background) !important; + color: var(--whoogle-dark-text) !important; } .search-container { - background-color: #222 !important; + background-color: var(--whoogle-dark-background) !important; } -.ZINbbc{ - background-color: #1a1a1a !important; +.ZINbbc { + background-color: var(--whoogle-dark-result-bg) !important; } -.bRsWnc{ - background-color: #1a1a1a !important; +.bRsWnc { + background-color: var(--whoogle-dark-result-bg) !important; +} + +#search-bar { + border: 2px solid var(--whoogle-dark-accent) !important; + border-radius: 8px; + color: var(--whoogle-dark-text) !important; +} + +#search-bar:focus { + color: var(--whoogle-dark-text) !important; +} + +#search-submit { + border: 1px solid var(--whoogle-dark-accent) !important; + background: var(--whoogle-dark-accent) !important; + color: var(--whoogle-dark-background) !important; +} + +.info-text { + color: var(--whoogle-dark-contrast-text) !important; + opacity: 75%; +} + +.collapsible { + color: var(--whoogle-dark-accent) !important; +} + +.collapsible:after { + color: var(--whoogle-dark-accent) !important; +} + +.active { + background-color: var(--whoogle-dark-accent) !important; + color: var(--whoogle-dark-contrast-text) !important; +} + +.content { + background-color: var(--whoogle-dark-accent) !important; + color: var(--whoogle-contrast-text) !important; +} + +.active:after { + color: var(--whoogle-dark-contrast-text); +} + +#gh-link { + color: var(--whoogle-dark-accent); +} + +.autocomplete-items { + border: 1px solid #685e79; +} + +.autocomplete-items div { + color: #fff; + background-color: #222; + border-bottom: 1px solid #242424; +} + +.autocomplete-items div:hover { + background-color: #404040; +} + +.autocomplete-active { + background-color: var(--whoogle-dark-accent) !important; + color: var(--whoogle-dark-background) !important; } diff --git a/app/static/css/light-theme.css b/app/static/css/light-theme.css new file mode 100644 index 0000000..a878c5e --- /dev/null +++ b/app/static/css/light-theme.css @@ -0,0 +1,130 @@ +html { + background: var(--whoogle-background) !important; +} + +body { + background: var(--whoogle-background) !important; +} + +div { + color: var(--whoogle-text) !important; +} + +label { + color: var(--whoogle-contrast-text) !important; +} + +li a { + color: #4b8eaa !important; +} + +li { + color: var(--whoogle-text) !important; +} + +textarea { + background: var(--whoogle-background) !important; + color: var(--whoogle-text) !important; +} + +select { + background: var(--whoogle-background) !important; + color: var(--whoogle-text) !important; +} + +.ZINbbc { + background-color: var(--whoogle-result-bg) !important; +} + +.bRsWnc { + background-color: var(--whoogle-result-bg) !important; +} + +a:visited h3 div { + color: var(--whoogle-result-visited) !important; +} + +a:link h3 div { + color: var(--whoogle-result-title) !important; +} + +a:link div { + color: var(--whoogle-result-url) !important; +} + +div span { + color: var(--whoogle-secondary-text) !important; +} + +input { + background-color: var(--whoogle-background) !important; + color: var(--whoogle-text) !important; +} + +#search-bar { + color: var(--whoogle-text) !important; + background-color: var(--whoogle-background); +} + +.home-search { + border: 3px solid var(--whoogle-accent) !important; +} + +.search-container { + background-color: var(--whoogle-background) !important; +} + +#search-submit { + border: 1px solid var(--whoogle-accent) !important; + background: var(--whoogle-accent) !important; + color: var(--whoogle-background) !important; +} + +.info-text { + color: var(--whoogle-contrast-text) !important; + opacity: 75%; +} + +.collapsible { + color: var(--whoogle-accent) !important; +} + +.collapsible:after { + color: var(--whoogle-accent) !important; +} + +.active { + background-color: var(--whoogle-accent) !important; + color: var(--whoogle-contrast-text) !important; +} + +.content { + background-color: var(--whoogle-accent) !important; + color: var(--whoogle-contrast-text) !important; +} + +.active:after { + color: var(--whoogle-contrast-text); +} + +#gh-link { + color: var(--whoogle-accent); +} + +.autocomplete-items { + border: 1px solid #d4d4d4; +} + +.autocomplete-items div { + background-color: #fff; + border-bottom: 1px solid #d4d4d4; +} + +.autocomplete-items div:hover { + background-color: #e9e9e9; +} + +.autocomplete-active { + background-color: var(--whoogle-accent) !important; + color: var(--whoogle-background) !important; +} diff --git a/app/static/css/main.css b/app/static/css/main.css index 5b35bf6..937812a 100644 --- a/app/static/css/main.css +++ b/app/static/css/main.css @@ -10,6 +10,7 @@ body { } .search-container { + background: transparent !important; width: 80%; position: absolute; top: 50%; @@ -26,29 +27,21 @@ body { } #search-bar { + background: transparent !important; width: 100%; - border: 3px solid #685e79; padding: 5px; height: 40px; outline: none; font-size: 24px; - color: #685e79; border-radius: 10px 10px 0 0; max-width: 600px; background: rgba(0, 0, 0, 0); } -#search-bar:focus { - color: #685e79; -} - #search-submit { width: 100%; height: 40px; - border: 1px solid #685e79; - background: #685e79 !important; text-align: center; - color: #fff; cursor: pointer; font-size: 20px; align-content: center; @@ -70,7 +63,6 @@ button::-moz-focus-inner { .collapsible { outline: 0; background-color: rgba(0, 0, 0, 0); - color: #685e79; cursor: pointer; padding: 18px; width: 100%; @@ -81,14 +73,8 @@ button::-moz-focus-inner { border-radius: 10px 10px 0 0; } -.active { - background-color: #685e79; - color: white; -} - .collapsible:after { content: '\002B'; - color: #685e79; font-weight: bold; float: right; margin-left: 5px; @@ -96,7 +82,6 @@ button::-moz-focus-inner { .active:after { content: "\2212"; - color: white; } .content { @@ -104,8 +89,6 @@ button::-moz-focus-inner { max-height: 0; overflow: hidden; transition: max-height 0.2s ease-out; - background-color: #685e79; - color: white; border-radius: 0 0 10px 10px; } @@ -113,12 +96,6 @@ button::-moz-focus-inner { padding-bottom: 20px; } -.ua-span { - color: white; - -webkit-box-decoration-break: clone; - box-decoration-break: clone; -} - .hidden { display: none; } @@ -135,3 +112,49 @@ footer { font-style: italic; font-size: 12px; } + +#config-style { + resize: none; + overflow-y: scroll; + width: 100%; + height: 100px; +} + +.whoogle-logo { + display: none; +} + +.whoogle-svg { + width: 80%; + display: block; + margin: auto; + padding-bottom: 10px; +} + +.autocomplete { + position: relative; + display: inline-block; + width: 100%; +} + +.autocomplete-items { + position: absolute; + border-bottom: none; + border-top: none; + z-index: 99; + + /*position the autocomplete items to be the same width as the container:*/ + top: 100%; + left: 0; + right: 0; +} + +.autocomplete-items div { + padding: 10px; + cursor: pointer; +} + +details summary { + padding: 10px; + font-weight: bold; +} diff --git a/app/static/css/search-dark.css b/app/static/css/search-dark.css deleted file mode 100644 index efd923e..0000000 --- a/app/static/css/search-dark.css +++ /dev/null @@ -1,40 +0,0 @@ -.autocomplete { - position: relative; - display: inline-block; - width: 100%; -} - -.autocomplete-items { - position: absolute; - border: 1px solid #685e79; - border-bottom: none; - border-top: none; - z-index: 99; - - /*position the autocomplete items to be the same width as the container:*/ - top: 100%; - left: 0; - right: 0; -} - -.autocomplete-items div { - padding: 10px; - cursor: pointer; - color: #fff; - background-color: #222; - border-bottom: 1px solid #242424; -} - -.autocomplete-items div:hover { - background-color: #404040; -} - -.autocomplete-active { - background-color: #685e79 !important; - color: #ffffff; -} - -details summary { - padding: 10px; - font-weight: bold; -} diff --git a/app/static/css/search.css b/app/static/css/search.css deleted file mode 100644 index 155cfcf..0000000 --- a/app/static/css/search.css +++ /dev/null @@ -1,39 +0,0 @@ -.autocomplete { - position: relative; - display: inline-block; - width: 100%; -} - -.autocomplete-items { - position: absolute; - border: 1px solid #d4d4d4; - border-bottom: none; - border-top: none; - z-index: 99; - - /*position the autocomplete items to be the same width as the container:*/ - top: 100%; - left: 0; - right: 0; -} - -.autocomplete-items div { - padding: 10px; - cursor: pointer; - background-color: #fff; - border-bottom: 1px solid #d4d4d4; -} - -.autocomplete-items div:hover { - background-color: #e9e9e9; -} - -.autocomplete-active { - background-color: #685e79 !important; - color: #ffffff; -} - -details summary { - padding: 10px; - font-weight: bold; -} diff --git a/app/static/css/variables.css b/app/static/css/variables.css new file mode 100644 index 0000000..efb6d3a --- /dev/null +++ b/app/static/css/variables.css @@ -0,0 +1,24 @@ +/* Colors */ +:root { + /* LIGHT THEME COLORS */ + --whoogle-background: #fff; + --whoogle-accent: #685e79; + --whoogle-text: #000; + --whoogle-contrast-text: #fff; + --whoogle-secondary-text: #70757a; + --whoogle-result-bg: #fff; + --whoogle-result-title: #1967d2; + --whoogle-result-url: #0d652d; + --whoogle-result-visited: #4b11a8; + + /* DARK THEME COLORS */ + --whoogle-dark-background: #222; + --whoogle-dark-accent: #685e79; + --whoogle-dark-text: #fff; + --whoogle-dark-contrast-text: #000; + --whoogle-dark-secondary-text: #bbb; + --whoogle-dark-result-bg: #000; + --whoogle-dark-result-title: #1967d2; + --whoogle-dark-result-url: #4b11a8; + --whoogle-dark-result-visited: #bbbbff; +} diff --git a/app/static/img/whoogle.svg b/app/static/img/whoogle.svg new file mode 100644 index 0000000..41a783e --- /dev/null +++ b/app/static/img/whoogle.svg @@ -0,0 +1 @@ + diff --git a/app/static/js/controller.js b/app/static/js/controller.js index 3ab8ca7..8399220 100644 --- a/app/static/js/controller.js +++ b/app/static/js/controller.js @@ -1,14 +1,3 @@ -// Whoogle configurations that use boolean values and checkboxes -CONFIG_BOOLS = [ - "nojs", "dark", "safe", "alts", "new_tab", "get_only", "tor" -]; - -// Whoogle configurations that use string values and input fields -CONFIG_STRS = [ - "near", "url" -]; - - const setupSearchLayout = () => { // Setup search field const searchBar = document.getElementById("search-bar"); @@ -28,33 +17,6 @@ const setupSearchLayout = () => { }); }; -const fillConfigValues = () => { - // Request existing config info - let xhrGET = new XMLHttpRequest(); - xhrGET.open("GET", "config"); - xhrGET.onload = function() { - if (xhrGET.readyState === 4 && xhrGET.status !== 200) { - alert("Error loading Whoogle config"); - return; - } - - // Allow for updating/saving config values - let configSettings = JSON.parse(xhrGET.responseText); - - CONFIG_STRS.forEach(function(item) { - let configElement = document.getElementById("config-" + item.replace("_", "-")); - configElement.value = configSettings[item] ? configSettings[item] : ""; - }); - - CONFIG_BOOLS.forEach(function(item) { - let configElement = document.getElementById("config-" + item.replace("_", "-")); - configElement.checked = !!configSettings[item]; - }); - }; - - xhrGET.send(); -}; - const setupConfigLayout = () => { // Setup whoogle config const collapsible = document.getElementById("config-collapsible"); @@ -69,8 +31,6 @@ const setupConfigLayout = () => { content.classList.toggle("open"); }); - - fillConfigValues(); }; const loadConfig = event => { diff --git a/app/misc/countries.json b/app/static/settings/countries.json similarity index 100% rename from app/misc/countries.json rename to app/static/settings/countries.json diff --git a/app/misc/languages.json b/app/static/settings/languages.json similarity index 100% rename from app/misc/languages.json rename to app/static/settings/languages.json diff --git a/app/templates/display.html b/app/templates/display.html index 30eba0a..9913f55 100644 --- a/app/templates/display.html +++ b/app/templates/display.html @@ -5,11 +5,10 @@ - + - {% if dark_mode %} - - {% endif %} + + {{ query }} - Whoogle Search @@ -17,7 +16,7 @@ {{ response|safe }}