diff --git a/README.md b/README.md index 5bc3b1c..af1d11e 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,17 @@ A self-hosted private and anonymous [metasearch engine](https://en.wikipedia.org ## Comparison to other search engines -| Name | Works without JavaScript | Music search | Torrent search | API | Scalable | Not Resource Hungry | Dynamic Page Loading | -| ------------- | ------------------ | --------------------------- | ----------------- | ------ | ------------------- | ---------------------------------------------- | ---------------------- | -| Whoogle [1] | ✅ | ❓ | ❌ | ❌ | ❌ | ❓ Moderate | ❓ Not specified | -| Araa-Search | ✅ | ❌ | ✅ | ✅ [2] | ❌ | ❌ Very resource hungry | ❌ | -| LibreY | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ Moderate 200-400mb~ | ❌ | -| 4get | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ Moderate 200-400mb~ | ❌ | -| Warp | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ about 15-20MiB at idle, 17-22MiB when searching | ✅ | +| Feature | Whoogle | Araa-Search | LibreY | 4get | *Warp* | +| :----------------------------------- | ------------------ | ------------------------- | ------------------------ | ------------------------ | ---------------------------------------------------- | +| Works without JavaScript | ✅ | ✅ | ✅ | ✅ | ✅ | +| Music search | ❓ | ❌ | ❌ | ✅ | ✅ | +| Torrent search | ❌ | ✅ | ✅ | ❌ | ✅ | +| API | ❌ | ✅ | ✅ | ✅ | ✅ | +| Scalable | ❌ | ❌ | ❌ | ❌ | ✅ | +| Not Resource Hungry | ❓ Moderate | ❌ Very resource hungry | ❌ Moderate 200-400mb~ | ❌ Moderate 200-400mb~ | ✅ about 15-20MiB at idle, 17-22MiB when searching | +| Dynamic Page Loading | ❓ Not specified | ❌ | ❌ | ❌ | ✅ | +| User themable | ❌ | ✅ | ❌ | ❌ | ✅ | +| It has dildo as logo, unironically | ❌ | ❌ | ❌ | ✅ | ❌ | [1]: I was not able to check this since their site does not work, same for the community instances. @@ -70,4 +74,4 @@ chmod +x ./run.sh ./run.sh ``` -*Its that easy!* \ No newline at end of file +*Its that easy!* diff --git a/main.go b/main.go index 392aab8..65c272b 100755 --- a/main.go +++ b/main.go @@ -169,9 +169,8 @@ func runServer() { http.HandleFunc("/search", handleSearch) http.HandleFunc("/img_proxy", handleImageProxy) http.HandleFunc("/node", handleNodeRequest) - http.HandleFunc("/settings", func(w http.ResponseWriter, r *http.Request) { - http.ServeFile(w, r, "templates/settings.html") - }) + http.HandleFunc("/settings", handleSettings) + http.HandleFunc("/save-settings", handleSaveSettings) http.HandleFunc("/opensearch.xml", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/opensearchdescription+xml") http.ServeFile(w, r, "static/opensearch.xml") diff --git a/static/css/black.css b/static/css/black.css new file mode 100644 index 0000000..9661246 --- /dev/null +++ b/static/css/black.css @@ -0,0 +1,74 @@ +:root { + --html-bg: #000000; + --font-fg: #fafafa; + --fg: #BABCBE; + + --search-bg: #000000; + --search-bg-input: #000000; + --search-bg-input-border: #5f6368; + --search-select: #282828; + + --border: #707070; + + --link: #8ab4f8; + --link-visited: #c58af9; + + --snip-border: #303134; + --snip-background: #282828; + --snip-text: #f1f3f4; + + --settings-border: #5f6368; + --button: #000000; + + --footer-bg: #161616; + --footer-font: #999da2; + + --highlight: #bcc0c3; + + --blue: #8ab4f8; + + --green: #31b06e; + + --search-button: #BABCBE; + + --image-view: #161616; + --image-view-titlebar: #161616; + --view-image-color: #000000; + --image-select: #303030; + --fff: #fff; + + --publish-info: #7f869e; + + color-scheme: dark; +} + +.calc-btn:hover { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); +} + +.calc-btn-2:hover { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); +} + +.calc-btn-2 { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +.calc-btn { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +.calc { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); +} + +.view-image-search { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +.view-image-search:hover { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); +} diff --git a/static/css/latte.css b/static/css/latte.css new file mode 100644 index 0000000..b217da7 --- /dev/null +++ b/static/css/latte.css @@ -0,0 +1,100 @@ +:root { + --rosewater: #f5e0dc; + --flamingo: #f2cdcd; + --pink: #f5c2e7; + --mauve: #cba6f7; + --red: #f38ba8; + --maroon: #eba0ac; + --peach: #fab387; + --yellow: #f9e2af; + --green: #a6e3a1; + --teal: #94e2d5; + --sky: #89dceb; + --sapphire: #74c7ec; + --blue: #89b4fa; + --lavender: #b4befe; + --text: #cdd6f4; + --subtext1: #bac2de; + --subtext0: #a6adc8; + --overlay2: #9399b2; + --overlay1: #7f849c; + --overlay0: #6c7086; + --surface2: #585b70; + --surface1: #45475a; + --surface0: #313244; + --base: #1e1e2e; + --mantle: #181825; + --crust: #11111b; + + --html-bg: var(--base); + --font-fg: var(--text); + --fg: var(--subtext0); + + --search-bg: var(--mantle); + --search-bg-input: var(--surface1); + --search-bg-input-border: var(--overlay0); + --search-select: var(--surface0); + + --border: var(--overlay0); + + --link: var(--blue); + --link-visited: var(--mauve); + + --snip-border: var(--surface1); + --snip-background: var(--surface0); + --snip-text: var(--text); + + --settings-border: var(--overlay1); + --button: var(--surface1); + + --footer-bg: var(--mantle); + --footer-font: var(--overlay1); + + --highlight: var(--subtext1); + + --blue: var(--blue); + --green: var(--green); + + --search-button: var(--subtext0); + + --image-view: var(--mantle); + --image-view-titlebar: var(--mantle); + --view-image-color: var(--crust); + --image-select: var(--surface1); + --fff: var(--text); + + --publish-info: var(--overlay2); + + color-scheme: dark; +} + +.calc-btn:hover { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); +} + +.calc-btn-2:hover { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); +} + +.calc-btn-2 { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +.calc-btn { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +.calc { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); +} + +.view-image-search { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +.view-image-search:hover { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); +} diff --git a/static/css/mocha.css b/static/css/mocha.css new file mode 100644 index 0000000..543332f --- /dev/null +++ b/static/css/mocha.css @@ -0,0 +1,100 @@ +:root { + --rosewater: #dc8a78; + --flamingo: #dd7878; + --pink: #ea76cb; + --mauve: #8839ef; + --red: #d20f39; + --maroon: #e64553; + --peach: #fe640b; + --yellow: #df8e1d; + --green: #40a02b; + --teal: #179299; + --sky: #04a5e5; + --sapphire: #209fb5; + --blue: #1e66f5; + --lavender: #7287fd; + --text: #4c4f69; + --subtext1: #5c5f77; + --subtext0: #6c6f85; + --overlay2: #7c7f93; + --overlay1: #8c8fa1; + --overlay0: #9ca0b0; + --surface2: #acb0be; + --surface1: #bcc0cc; + --surface0: #ccd0da; + --base: #eff1f5; + --mantle: #e6e9ef; + --crust: #dce0e8; + + --html-bg: var(--base); + --font-fg: var(--text); + --fg: var(--subtext0); + + --search-bg: var(--mantle); + --search-bg-input: var(--surface1); + --search-bg-input-border: var(--overlay0); + --search-select: var(--surface0); + + --border: var(--overlay0); + + --link: var(--blue); + --link-visited: var(--mauve); + + --snip-border: var(--surface1); + --snip-background: var(--surface0); + --snip-text: var(--text); + + --settings-border: var(--overlay1); + --button: var(--surface1); + + --footer-bg: var(--mantle); + --footer-font: var(--overlay1); + + --highlight: var(--subtext1); + + --blue: var(--blue); + --green: var(--green); + + --search-button: var(--subtext0); + + --image-view: var(--mantle); + --image-view-titlebar: var(--mantle); + --view-image-color: var(--crust); + --image-select: var(--surface1); + --fff: var(--text); + + --publish-info: var(--overlay2); + + color-scheme: light; +} + +.calc-btn:hover { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.15), 0 10px 10px rgba(0, 0, 0, 0.12); +} + +.calc-btn-2:hover { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.15), 0 10px 10px rgba(0, 0, 0, 0.12); +} + +.calc-btn-2 { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10), 0 1px 2px rgba(0, 0, 0, 0.14); + transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +.calc-btn { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10), 0 1px 2px rgba(0, 0, 0, 0.14); + transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +.calc { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15); +} + +.view-image-search { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10), 0 1px 2px rgba(0, 0, 0, 0.14); + transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +.view-image-search:hover { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.15), 0 10px 10px rgba(0, 0, 0, 0.12); +} diff --git a/static/css/night.css b/static/css/night.css new file mode 100644 index 0000000..0676672 --- /dev/null +++ b/static/css/night.css @@ -0,0 +1,74 @@ +:root { + --html-bg: #171b25; + --font-fg: #ebecf7; + --fg: #ebecf7; + + --search-bg: #0c0d0f; + --search-bg-input: #2e3443; + --search-bg-input-border: rgb(46, 52, 67); + --search-select: #3a445c; + + --border: rgb(46, 52, 67); + + --link: #a7b1fc; + --link-visited: #ad71bc; + + --snip-border: rgb(46, 52, 67); + --snip-background: #1e222d; + --snip-text: #f1f3f4; + + --settings-border: #5f6368; + --button: #0c0d0f; + + --footer-bg: #0c0d0f; + --footer-font: #ebecf7; + + --highlight: #ebecf7; + + --blue: #8ab4f8; + + --green: #31b06e; + + --image-view: #0c0d0f; + --image-view-titlebar: #0c0d0f; + --view-image-color: #000000; + --image-select: #303030; + --fff: #fff; + + --search-button: #BABCBE; + + --publish-info: #7f869e; + + color-scheme: dark; +} + +.calc-btn:hover { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); +} + +.calc-btn-2:hover { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); +} + +.calc-btn-2 { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +.calc-btn { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +.calc { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); +} + +.view-image-search { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); + transition: all 0.3s cubic-bezier(.25, .8, .25, 1); +} + +.view-image-search:hover { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); +} diff --git a/static/css/style-settings.css b/static/css/style-settings.css new file mode 100644 index 0000000..0dda333 --- /dev/null +++ b/static/css/style-settings.css @@ -0,0 +1,62 @@ + +/* settings.html */ + +.theme-link { + display: block; + text-decoration: none; + color: inherit; + width: 48%; + margin-bottom: 10px; + height: 150px; + position: relative; /* Make it possible to position the tooltip */ +} + +.theme-link img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 4px; + border: 1px solid var(--snip-border); + transition: border-color 0.3s ease; +} + +/* .theme-link:hover img { + border-color: var(--highlight); +} */ + +.theme-tooltip { + display: none; /* Hidden by default */ + position: absolute; + bottom: 10px; /* Position at the bottom of the image */ + left: 50%; + transform: translateX(-50%); + background-color: rgba(0, 0, 0, 0.7); /* Semi-transparent background */ + color: #fff; + padding: 5px 10px; + border-radius: 4px; + font-size: 14px; + white-space: nowrap; +} + +.theme-link:hover .theme-tooltip { + display: block; /* Show tooltip on hover */ +} + +.themes-settings-menu { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + background: var(--snip-background); + color: var(--fg); + border-radius: 4px; + padding: 10px; + gap: 10px; +} + +@media (max-width: 600px) { + .theme-link { + width: 100%; + } +} + +/* --- */ diff --git a/static/css/style.css b/static/css/style.css index 48d9127..e9cd93c 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -838,23 +838,6 @@ form.torrent-sort { display: initial; } -.themes-settings-menu { - background: var(--snip-background); - color: var(--fg); - border-radius: 4px; - height: 100%; - margin: 5px; - display: flex; - flex-wrap: wrap; - justify-content: space-between; -} - -.themes-settings-menu>div { - width: calc(50% - 10px); - margin: 5px; -} - - .view-image-search { border: 1px solid var(--snip-border); margin: 0; @@ -1873,8 +1856,6 @@ body, h1, p, a, input, button { } -/* --- */ - /* Ensuring dark theme compliance */ @media (prefers-color-scheme: dark) { .leaflet-control-locate, diff --git a/static/images/black.webp b/static/images/black.webp new file mode 100644 index 0000000..44386b5 Binary files /dev/null and b/static/images/black.webp differ diff --git a/static/images/dark.webp b/static/images/dark.webp index b72872a..ec0a27c 100644 Binary files a/static/images/dark.webp and b/static/images/dark.webp differ diff --git a/static/images/latte.webp b/static/images/latte.webp new file mode 100644 index 0000000..2a8f8d9 Binary files /dev/null and b/static/images/latte.webp differ diff --git a/static/images/light.webp b/static/images/light.webp index 4c7146d..be65002 100644 Binary files a/static/images/light.webp and b/static/images/light.webp differ diff --git a/static/images/mocha.webp b/static/images/mocha.webp new file mode 100644 index 0000000..d636958 Binary files /dev/null and b/static/images/mocha.webp differ diff --git a/static/images/night.webp b/static/images/night.webp new file mode 100644 index 0000000..3329268 Binary files /dev/null and b/static/images/night.webp differ diff --git a/templates/search.html b/templates/search.html index aa425a2..1300d4e 100755 --- a/templates/search.html +++ b/templates/search.html @@ -59,7 +59,7 @@

Settings

- +

Current theme: {{.Theme}}

diff --git a/templates/settings.html b/templates/settings.html index d106af3..73843f6 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -6,77 +6,85 @@ Settings - Ocásek + -
-

Ocásek

-
- - - + -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- - + +
+ +
+
+

Theme

+
+ + + +
+

Safe Search

+ +
+ +
+

Preferred Language

+ +
+ +
+

|

+
-
- - -
-
-
- -
-
-

SETTINGS ARE NOT IMPLEMENTED YET

-

Theme

- -
- -

Language

- -
- - - -

Privacy

- -
- -

- -
-
- +
diff --git a/user-settings.go b/user-settings.go index 80b8b04..9b7b5ee 100755 --- a/user-settings.go +++ b/user-settings.go @@ -1,6 +1,9 @@ package main -import "net/http" +import ( + "html/template" + "net/http" +) type UserSettings struct { Theme string @@ -57,4 +60,63 @@ func saveUserSettings(w http.ResponseWriter, settings UserSettings) { Secure: true, // Ensure cookie is sent over HTTPS only SameSite: http.SameSiteNoneMode, // Set SameSite to None }) + + printDebug("settings saved: %v", settings) +} + +func handleSaveSettings(w http.ResponseWriter, r *http.Request) { + if r.Method == "POST" { + // Load current settings + settings := loadUserSettings(r) + + // Update only the settings that were submitted in the form + if theme := r.FormValue("theme"); theme != "" { + settings.Theme = theme + } + if lang := r.FormValue("lang"); lang != "" { + settings.Language = lang + } + if safe := r.FormValue("safe"); safe != "" { + settings.SafeSearch = safe + } + + // Save the updated settings + saveUserSettings(w, settings) + + // Redirect back to the previous page or settings page + http.Redirect(w, r, r.FormValue("past"), http.StatusSeeOther) + } +} + +func handleSettings(w http.ResponseWriter, r *http.Request) { + // Load user settings + settings = loadUserSettings(r) + + data := struct { + LanguageOptions []LanguageOption + CurrentLang string + Theme string + Safe string + }{ + LanguageOptions: languageOptions, + CurrentLang: settings.Language, + Theme: settings.Theme, + Safe: settings.SafeSearch, + } + + printDebug("Rendering settings with data: %+v", data) + + tmpl, err := template.ParseFiles("templates/settings.html") + if err != nil { + printErr("Error parsing template: %s", err) + http.Error(w, "Internal Server Error", 500) + return + } + + err = tmpl.Execute(w, data) + if err != nil { + printErr("Error executing template: %s", err) + http.Error(w, "Internal Server Error", 500) + return + } }