From c3ed9017385342944badec46de263560c6ab07c8 Mon Sep 17 00:00:00 2001 From: frosty Date: Mon, 30 Mar 2026 10:37:46 +0300 Subject: feat: begin adding settings menu, move theme to settings --- src/Main.c | 4 + src/Routes/Home.c | 5 + src/Routes/Images.c | 8 +- src/Routes/Search.c | 8 +- src/Routes/Settings.c | 30 ++++++ src/Routes/Settings.h | 8 ++ src/Routes/SettingsSave.c | 28 ++++++ src/Routes/SettingsSave.h | 8 ++ src/Utility/Utility.c | 14 +++ src/Utility/Utility.h | 1 + static/main.css | 232 +++++++++++++++++++++++++++++++++++++++++++--- static/settings.svg | 4 + static/theme-dark.css | 10 ++ static/theme-light.css | 10 ++ templates/home.html | 10 +- templates/images.html | 8 +- templates/results.html | 8 +- templates/settings.html | 67 +++++++++++++ 18 files changed, 444 insertions(+), 19 deletions(-) create mode 100644 src/Routes/Settings.c create mode 100644 src/Routes/Settings.h create mode 100644 src/Routes/SettingsSave.c create mode 100644 src/Routes/SettingsSave.h create mode 100644 static/settings.svg create mode 100644 static/theme-dark.css create mode 100644 static/theme-light.css create mode 100644 templates/settings.html diff --git a/src/Main.c b/src/Main.c index 137cab5..326b5ae 100644 --- a/src/Main.c +++ b/src/Main.c @@ -13,6 +13,8 @@ #include "Routes/ImageProxy.h" #include "Routes/Images.h" #include "Routes/Search.h" +#include "Routes/Settings.h" +#include "Routes/SettingsSave.h" #include "Scraping/Scraping.h" Config global_config; @@ -97,6 +99,8 @@ int main() { set_handler("/search", results_handler); set_handler("/images", images_handler); set_handler("/proxy", image_proxy_handler); + set_handler("/settings", settings_handler); + set_handler("/save_settings", settings_save_handler); fprintf(stderr, "[INFO] Starting Omnisearch on %s:%d\n", cfg.host, cfg.port); diff --git a/src/Routes/Home.c b/src/Routes/Home.c index 4526a9d..c857663 100644 --- a/src/Routes/Home.c +++ b/src/Routes/Home.c @@ -1,14 +1,19 @@ #include "Home.h" +#include "../Utility/Utility.h" #include int home_handler(UrlParams *params) { (void)params; + char *theme = get_theme(""); + TemplateContext ctx = new_context(); + context_set(&ctx, "theme", theme); char *rendered_html = render_template("home.html", &ctx); send_response(rendered_html); free(rendered_html); free_context(&ctx); + free(theme); return 0; } diff --git a/src/Routes/Images.c b/src/Routes/Images.c index 0f8ff1e..03eb280 100644 --- a/src/Routes/Images.c +++ b/src/Routes/Images.c @@ -1,6 +1,7 @@ #include "Images.h" #include "../Scraping/ImageScraping.h" #include "../Utility/Unescape.h" +#include "../Utility/Utility.h" #include "Config.h" int images_handler(UrlParams *params) { @@ -29,6 +30,11 @@ int images_handler(UrlParams *params) { snprintf(two_prev_str, sizeof(two_prev_str), "%d", page > 2 ? page - 2 : 0); snprintf(two_next_str, sizeof(two_next_str), "%d", page + 2); context_set(&ctx, "query", raw_query); + + char *theme = get_theme(""); + context_set(&ctx, "theme", theme); + free(theme); + context_set(&ctx, "page", page_str); context_set(&ctx, "prev_page", prev_str); context_set(&ctx, "next_page", next_str); @@ -39,7 +45,7 @@ int images_handler(UrlParams *params) { context_set(&ctx, "query", display_query); if (!raw_query || strlen(raw_query) == 0) { - send_response("

No query provided

"); + send_redirect("/"); if (display_query) free(display_query); free_context(&ctx); diff --git a/src/Routes/Search.c b/src/Routes/Search.c index 5f89752..81e43d4 100644 --- a/src/Routes/Search.c +++ b/src/Routes/Search.c @@ -7,6 +7,7 @@ #include "../Scraping/Scraping.h" #include "../Utility/Display.h" #include "../Utility/Unescape.h" +#include "../Utility/Utility.h" #include "Config.h" #include #include @@ -401,12 +402,17 @@ int results_handler(UrlParams *params) { } context_set(&ctx, "query", raw_query); + + char *theme = get_theme(""); + context_set(&ctx, "theme", theme); + free(theme); + char page_str[16]; snprintf(page_str, sizeof(page_str), "%d", page); context_set(&ctx, "page", page_str); if (!raw_query || strlen(raw_query) == 0) { - send_response("

No query provided

"); + send_redirect("/"); free_context(&ctx); return -1; } diff --git a/src/Routes/Settings.c b/src/Routes/Settings.c new file mode 100644 index 0000000..05edc56 --- /dev/null +++ b/src/Routes/Settings.c @@ -0,0 +1,30 @@ +#include "Settings.h" +#include "../Utility/Utility.h" +#include +#include + +int settings_handler(UrlParams *params) { + const char *query = ""; + if (params) { + for (int i = 0; i < params->count; i++) { + if (strcmp(params->params[i].key, "q") == 0) { + query = params->params[i].value; + break; + } + } + } + + char *theme = get_theme("system"); + + TemplateContext ctx = new_context(); + context_set(&ctx, "query", query); + context_set(&ctx, "theme", theme); + char *rendered_html = render_template("settings.html", &ctx); + send_response(rendered_html); + + free(rendered_html); + free(theme); + free_context(&ctx); + + return 0; +} diff --git a/src/Routes/Settings.h b/src/Routes/Settings.h new file mode 100644 index 0000000..269c085 --- /dev/null +++ b/src/Routes/Settings.h @@ -0,0 +1,8 @@ +#ifndef SETTINGS_H +#define SETTINGS_H + +#include + +int settings_handler(UrlParams *params); + +#endif diff --git a/src/Routes/SettingsSave.c b/src/Routes/SettingsSave.c new file mode 100644 index 0000000..d286507 --- /dev/null +++ b/src/Routes/SettingsSave.c @@ -0,0 +1,28 @@ +#include "SettingsSave.h" +#include +#include + +int settings_save_handler(UrlParams *params) { + const char *theme = ""; + const char *query = ""; + + if (params) { + for (int i = 0; i < params->count; i++) { + if (strcmp(params->params[i].key, "theme") == 0) { + theme = params->params[i].value; + } else if (strcmp(params->params[i].key, "q") == 0) { + query = params->params[i].value; + } + } + } + + if (strlen(theme) > 0) { + set_cookie("theme", theme, "Fri, 31 Dec 2038 23:59:59 GMT", "/", false, false); + } + + char redirect_url[512]; + snprintf(redirect_url, sizeof(redirect_url), "/settings?q=%s", query); + send_redirect(redirect_url); + + return 0; +} diff --git a/src/Routes/SettingsSave.h b/src/Routes/SettingsSave.h new file mode 100644 index 0000000..e10cc2f --- /dev/null +++ b/src/Routes/SettingsSave.h @@ -0,0 +1,8 @@ +#ifndef SETTINGS_SAVE_H +#define SETTINGS_SAVE_H + +#include + +int settings_save_handler(UrlParams *params); + +#endif diff --git a/src/Utility/Utility.c b/src/Utility/Utility.c index 3be4ef4..b4ad91d 100644 --- a/src/Utility/Utility.c +++ b/src/Utility/Utility.c @@ -1,4 +1,7 @@ #include "Utility.h" +#include +#include +#include int hex_to_int(char c) { if (c >= '0' && c <= '9') @@ -9,3 +12,14 @@ int hex_to_int(char c) { return c - 'A' + 10; return -1; } + +char *get_theme(const char *default_theme) { + char *cookie = get_cookie("theme"); + if (cookie && + (strcmp(cookie, "light") == 0 || + strcmp(cookie, "dark") == 0)) { + return cookie; + } + free(cookie); + return strdup(default_theme); +} diff --git a/src/Utility/Utility.h b/src/Utility/Utility.h index 3b0181c..e67282f 100644 --- a/src/Utility/Utility.h +++ b/src/Utility/Utility.h @@ -2,5 +2,6 @@ #define UTILITY_H int hex_to_int(char c); +char *get_theme(const char *default_theme); #endif diff --git a/static/main.css b/static/main.css index 6f899cf..5f7c0f9 100644 --- a/static/main.css +++ b/static/main.css @@ -25,12 +25,19 @@ box-sizing: border-box; } +html { + height:100%; +} + body { background-color:var(--bg-main); + background-image:radial-gradient(circle at top right, var(--bg-card) 0%, var(--bg-main) 100%); + background-attachment:fixed; color:var(--text-primary); font-family:system-ui,-apple-system,sans-serif; margin:0; padding:0; + min-height:100%; -webkit-tap-highlight-color: transparent; } @@ -44,13 +51,12 @@ img[src=""] { align-items: center; min-height: 100vh; padding: 20px; - background: radial-gradient(circle at top right, var(--bg-card) 0%, var(--bg-main) 100%); } .view-home .container { width: 100%; max-width: 580px; - margin: 0 auto; + margin: 0 auto; text-align: center; display: flex; flex-direction: column; @@ -100,11 +106,56 @@ img[src=""] { background:var(--bg-card); color:var(--text-primary); border-color:var(--border); + text-decoration:none; + display:inline-flex; + align-items:center; + padding:10px 24px; + border-radius:8px; + font-weight:600; + font-size:0.9rem; + cursor:pointer; + transition:all 0.2s; + border:1px solid var(--border); } .view-home .btn-secondary:hover { background:var(--border); border-color:var(--text-secondary); } +.home-settings-btn { + position:fixed; + top:27px; + right:60px; + width:24px; + height:24px; + background-color:var(--text-primary); + -webkit-mask-image:url('/static/settings.svg'); + mask-image:url('/static/settings.svg'); + mask-size:contain; + mask-repeat:no-repeat; + mask-position:center; + text-decoration:none; +} +.nav-settings-icon { + width:24px; + height:24px; + flex-shrink:0; + margin-left:auto; + margin-top:3px; + background-color:var(--text-secondary); + -webkit-mask-image:url('/static/settings.svg'); + mask-image:url('/static/settings.svg'); + mask-size:100% 100%; + transition:background-color 0.2s; + text-decoration:none; +} +.nav-settings-icon:hover, +.nav-settings-icon.active { + background-color:var(--text-primary); +} +.nav-settings-link { + display:none; + margin-left:auto; +} header { display:flex; align-items:center; @@ -112,6 +163,7 @@ header { padding:15px 60px; border-bottom:1px solid var(--border); background:var(--bg-main); + width:100%; } .search-form { flex-grow:1; @@ -145,11 +197,11 @@ h1 span { padding:0 60px; border-bottom:1px solid var(--border); background:var(--bg-main); + width:100%; } .nav-container { display:flex; gap:30px; - max-width:1200px; } .nav-tabs a { padding:14px 0; @@ -168,6 +220,9 @@ h1 span { color:var(--accent); border-bottom-color:var(--accent); } +.nav-right { + margin-left:auto; +} .image-results-container { padding:30px 60px; } @@ -473,19 +528,23 @@ h1 span { @media (max-width:1200px) { - body { - padding-left: 16px; - padding-right: 16px; - } .content-layout { grid-template-columns:1fr; padding:20px 30px; gap:20px; } + header { + gap:20px; + } .results-container,.infobox-sidebar { grid-column:1; max-width:100%; } + .settings-layout { + padding:20px 30px; + display:flex; + justify-content:center; + } .infobox-sidebar { order:-1; } @@ -498,9 +557,11 @@ h1 span { } @media (max-width:768px) { - body { - padding-left: 16px; - padding-right: 16px; + .nav-settings-icon { + display:none; + } + .nav-settings-link { + display:inline; } header { flex-direction:column; @@ -532,7 +593,7 @@ h1 span { font-size:0.95rem; } .content-layout { - padding:16px; + padding:16px 16px 16px 40px; gap:16px; } .result { @@ -591,7 +652,6 @@ h1 span { display: flex; justify-content: center; align-items: center; - transform: translateY(-5vh); padding:20px 16px; min-height: 100vh; } @@ -621,6 +681,12 @@ h1 span { } @media (max-width:600px) { + .content-layout { + padding:16px 16px 16px 28px; + } + .settings-layout { + padding:12px 0; + } header { padding:12px 12px; } @@ -657,3 +723,145 @@ h1 span { font-size:0.75rem; } } + +.settings-layout { + padding:30px 60px 30px 260px; +} + +.settings-container { + max-width:700px; +} + +.settings-title { + font-size:1.8rem; + font-weight:700; + margin:0 0 32px 0; + letter-spacing:-0.5px; +} + +.settings-section { + background:var(--bg-card); + border:1px solid var(--border); + border-radius:12px; + padding:24px; + margin-bottom:32px; +} + +.settings-section-title { + font-size:1.1rem; + font-weight:700; + margin:0 0 4px 0; +} + +.settings-section-desc { + color:var(--text-secondary); + font-size:0.9rem; + margin:0 0 20px 0; + line-height:1.4; +} + +.settings-field { + display:flex; + align-items:center; + justify-content:space-between; + padding:10px 0; +} + +.settings-field + .settings-field { + border-top:1px solid var(--border); +} + +.settings-label { + font-size:0.95rem; + color:var(--text-primary); +} + +.settings-select { + padding:8px 12px; + border-radius:8px; + border:1px solid var(--border); + background:var(--bg-main); + color:var(--text-primary); + font-size:0.9rem; + outline:none; + cursor:pointer; + transition:border-color 0.2s; +} + +.settings-select:focus { + border-color:var(--accent); +} + +.settings-actions { + display:flex; + gap:12px; + margin-top:8px; + padding-bottom:40px; + justify-content:flex-start; +} + +.settings-actions .btn-primary { + background:var(--accent); + color:var(--bg-main); + border:1px solid transparent; + padding:10px 24px; + border-radius:8px; + font-weight:600; + font-size:0.9rem; + cursor:pointer; + transition:all 0.2s; + touch-action:manipulation; +} + +.settings-actions .btn-primary:hover { + filter:brightness(1.1); + transform:translateY(-1px); +} + +.settings-actions .btn-secondary { + background:var(--bg-card); + color:var(--text-primary); + border:1px solid var(--border); + padding:10px 24px; + border-radius:8px; + font-weight:600; + font-size:0.9rem; + cursor:pointer; + transition:all 0.2s; + touch-action:manipulation; +} + +.settings-actions .btn-secondary:hover { + background:var(--border); + border-color:var(--text-secondary); +} + +@media (max-width:768px) { + .settings-layout { + padding:12px; + display:block; + } + .settings-container { + max-width:100%; + } + .settings-title { + font-size:1.4rem; + margin-bottom:24px; + } + .settings-section { + padding:16px; + } + .settings-field { + flex-direction:column; + align-items:stretch; + gap:8px; + } + .settings-actions { + flex-direction:column; + } + .settings-actions .btn-primary, + .settings-actions .btn-secondary { + width:100%; + text-align:center; + } +} diff --git a/static/settings.svg b/static/settings.svg new file mode 100644 index 0000000..4aebf8f --- /dev/null +++ b/static/settings.svg @@ -0,0 +1,4 @@ + + + + diff --git a/static/theme-dark.css b/static/theme-dark.css new file mode 100644 index 0000000..246aabe --- /dev/null +++ b/static/theme-dark.css @@ -0,0 +1,10 @@ +:root { + --bg-main: #121212; + --bg-card: #1e1e1e; + --border: #333333; + --text-primary: #ffffff; + --text-secondary: #a0a0a0; + --text-muted: #d1d1d1; + --accent: #e2e2e2; + --accent-glow: rgba(255,255,255,0.1); +} diff --git a/static/theme-light.css b/static/theme-light.css new file mode 100644 index 0000000..1c69377 --- /dev/null +++ b/static/theme-light.css @@ -0,0 +1,10 @@ +:root { + --bg-main: #ffffff; + --bg-card: #f8f9fa; + --border: #e0e0e0; + --text-primary: #1a1a1a; + --text-secondary: #5f6368; + --text-muted: #757575; + --accent: #202124; + --accent-glow: rgba(0,0,0,0.05); +} diff --git a/templates/home.html b/templates/home.html index 90fc904..ae00824 100644 --- a/templates/home.html +++ b/templates/home.html @@ -8,7 +8,9 @@ OmniSearch - + {{if theme == "light"}}{{endif}} + {{if theme == "dark"}}{{endif}} + @@ -30,11 +32,13 @@ Search + + diff --git a/templates/images.html b/templates/images.html index f04867b..92ab7b5 100644 --- a/templates/images.html +++ b/templates/images.html @@ -7,8 +7,10 @@ OmniSearch Images - {{query}} - + + {{if theme == "light"}}{{endif}} + {{if theme == "dark"}}{{endif}} @@ -20,6 +22,7 @@ +
diff --git a/templates/results.html b/templates/results.html index 57c2265..4128245 100644 --- a/templates/results.html +++ b/templates/results.html @@ -8,7 +8,9 @@ OmniSearch - {{query}} - + {{if theme == "light"}}{{endif}} + {{if theme == "dark"}}{{endif}} + @@ -24,6 +26,7 @@ +
diff --git a/templates/settings.html b/templates/settings.html new file mode 100644 index 0000000..780e438 --- /dev/null +++ b/templates/settings.html @@ -0,0 +1,67 @@ + + + + + + + + OmniSearch - Settings + + + {{if theme == "light"}}{{endif}} + {{if theme == "dark"}}{{endif}} + + + + + +
+

+ OmniSearch +

+
+ +
+ +
+ +
+
+
+ +
+

Theme

+

Choose your preferred colour scheme.

+
+ + +
+
+
+ +
+
+
+
+ + + -- cgit v1.2.3