aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Main.c4
-rw-r--r--src/Routes/Home.c5
-rw-r--r--src/Routes/Images.c8
-rw-r--r--src/Routes/Search.c8
-rw-r--r--src/Routes/Settings.c30
-rw-r--r--src/Routes/Settings.h8
-rw-r--r--src/Routes/SettingsSave.c28
-rw-r--r--src/Routes/SettingsSave.h8
-rw-r--r--src/Utility/Utility.c14
-rw-r--r--src/Utility/Utility.h1
-rw-r--r--static/main.css232
-rw-r--r--static/settings.svg4
-rw-r--r--static/theme-dark.css10
-rw-r--r--static/theme-light.css10
-rw-r--r--templates/home.html10
-rw-r--r--templates/images.html8
-rw-r--r--templates/results.html8
-rw-r--r--templates/settings.html67
18 files changed, 444 insertions, 19 deletions
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 <stdlib.h>
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("<h1>No query provided</h1>");
+ 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 <ctype.h>
#include <pthread.h>
@@ -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("<h1>No query provided</h1>");
+ 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 <stdlib.h>
+#include <string.h>
+
+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 <beaker.h>
+
+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 <stdlib.h>
+#include <string.h>
+
+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 <beaker.h>
+
+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 <beaker.h>
+#include <stdlib.h>
+#include <string.h>
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 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+ <circle cx="12" cy="12" r="3"/>
+ <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
+</svg>
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
</title>
<link rel="stylesheet" href="static/main.css">
- <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
+ {{if theme == "light"}}<link rel="stylesheet" href="static/theme-light.css">{{endif}}
+ {{if theme == "dark"}}<link rel="stylesheet" href="static/theme-dark.css">{{endif}}
+ <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<link rel="search"
type="application/opensearchdescription+xml"
title="OmniSearch" href="/opensearch.xml">
@@ -30,11 +32,13 @@
Search
</button>
<button type="submit" name="btnI" value="1" class="btn-secondary">
- Surprise me
- </div>
+ Surprise me
+ </button>
+ </div>
</form>
</div>
</div>
+ <a href="/settings" class="home-settings-btn" title="Settings"></a>
</body>
</html>
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 @@
<title>
OmniSearch Images - {{query}}
</title>
- <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
+ <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<link rel="stylesheet" href="static/main.css">
+ {{if theme == "light"}}<link rel="stylesheet" href="static/theme-light.css">{{endif}}
+ {{if theme == "dark"}}<link rel="stylesheet" href="static/theme-dark.css">{{endif}}
</head>
<body class="images-view">
@@ -20,6 +22,7 @@
<input name="q" autocomplete="off"="text" class="search-box" placeholder="Search for images..."
value="{{query}}">
</form>
+ <a href="/settings?q={{query}}" class="nav-settings-icon" title="Settings"></a>
</header>
<nav class="nav-tabs">
<div class="nav-container">
@@ -29,6 +32,9 @@
<a href="/images?q={{query}}" class="active">
Images
</a>
+ <a href="/settings?q={{query}}" class="nav-settings-link">
+ Settings
+ </a>
</div>
</nav>
<main class="image-results-container">
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}}
</title>
<link rel="stylesheet" href="static/main.css">
- <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
+ {{if theme == "light"}}<link rel="stylesheet" href="static/theme-light.css">{{endif}}
+ {{if theme == "dark"}}<link rel="stylesheet" href="static/theme-dark.css">{{endif}}
+ <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<link rel="search"
type="application/opensearchdescription+xml"
title="OmniSearch" href="/opensearch.xml">
@@ -24,6 +26,7 @@
<input name="q" type="text" class="search-box" autocomplete="off" placeholder="Search the web..."
value="{{query}}">
</form>
+ <a href="/settings?q={{query}}" class="nav-settings-icon" title="Settings"></a>
</header>
<nav class="nav-tabs">
<div class="nav-container">
@@ -33,6 +36,9 @@
<a href="/images?q={{query}}">
Images
</a>
+ <a href="/settings?q={{query}}" class="nav-settings-link">
+ Settings
+ </a>
</div>
</nav>
<div class="content-layout">
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 @@
+<!DOCTYPE html>
+<html lang="en">
+
+ <head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0">
+ <title>
+ OmniSearch - Settings
+ </title>
+ <link rel="stylesheet" href="static/main.css">
+ {{if theme == "light"}}<link rel="stylesheet" href="static/theme-light.css">{{endif}}
+ {{if theme == "dark"}}<link rel="stylesheet" href="static/theme-dark.css">{{endif}}
+ <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
+ <link rel="search"
+ type="application/opensearchdescription+xml"
+ title="OmniSearch" href="/opensearch.xml">
+ </head>
+
+ <body class="settings-view">
+ <header>
+ <h1>
+ Omni<span>Search</span>
+ </h1>
+ <form action="/search" method="GET" class="search-form">
+ <input name="q" type="text" class="search-box" autocomplete="off" placeholder="Search the web..."
+ value="{{query}}">
+ </form>
+ <a href="/settings?q={{query}}" class="nav-settings-icon active" title="Settings"></a>
+ </header>
+ <nav class="nav-tabs">
+ <div class="nav-container">
+ <a href="/search?q={{query}}">
+ All
+ </a>
+ <a href="/images?q={{query}}">
+ Images
+ </a>
+ <a href="/settings" class="active nav-settings-link">
+ Settings
+ </a>
+ </div>
+ </nav>
+ <div class="settings-layout">
+ <main class="settings-container">
+ <form action="/save_settings" method="GET">
+ <input type="hidden" name="q" value="{{query}}">
+ <section class="settings-section">
+ <h3 class="settings-section-title">Theme</h3>
+ <p class="settings-section-desc">Choose your preferred colour scheme.</p>
+ <div class="settings-field">
+ <label class="settings-label" for="theme">Appearance</label>
+ <select id="theme" name="theme" class="settings-select">
+ <option value="system" {{if theme == "system"}}selected{{endif}}>System</option>
+ <option value="light" {{if theme == "light"}}selected{{endif}}>Light</option>
+ <option value="dark" {{if theme == "dark"}}selected{{endif}}>Dark</option>
+ </select>
+ </div>
+ </section>
+ <div class="settings-actions">
+ <button type="submit" class="btn-primary">Save Settings</button>
+ </div>
+ </form>
+ </main>
+ </div>
+ </body>
+
+</html>