media query theme (#139)

* feat: use css media query to derive theme

* fix: rename alt for toggle images

* feat: remove no-cache middleware
This commit is contained in:
httpjamesm 2024-06-20 00:18:22 -04:00 committed by GitHub
parent b0ae8a50b5
commit e409176642
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 17 additions and 77 deletions

View File

@ -35,7 +35,6 @@ func main() {
r.Use(gin.Recovery()) r.Use(gin.Recovery())
r.Use(middleware.XssPreventionHeaders()) r.Use(middleware.XssPreventionHeaders())
r.Use(middleware.NoCacheMiddleware())
r.Use(middleware.OptionsMiddleware()) r.Use(middleware.OptionsMiddleware())
r.Use(middleware.Ratelimit()) r.Use(middleware.Ratelimit())

View File

@ -11,17 +11,19 @@
--link-color: #92adff; --link-color: #92adff;
} }
[data-theme='light'] { @media (prefers-color-scheme: light) {
--main-bg: #dbdbdb; :root {
--text-color: #000; --main-bg: #dbdbdb;
--muted-text-color: #636363; --text-color: #000;
--code-bg: #36383d; --muted-text-color: #636363;
--code-fg: #ffffff; --code-bg: #36383d;
--input-bg: #bcbcbc; --code-fg: #ffffff;
--input-bg-hover: #a8a8a8; --input-bg: #bcbcbc;
--meta-bg: #aaa8a8; --input-bg-hover: #a8a8a8;
--divider-color: #b5b5b5; --meta-bg: #aaa8a8;
--link-color: #335ad0; --divider-color: #b5b5b5;
--link-color: #335ad0;
}
} }
a { a {
@ -76,4 +78,4 @@ details {
.fw-nowrap { .fw-nowrap {
flex-wrap: nowrap; flex-wrap: nowrap;
} }

View File

@ -1,12 +0,0 @@
package middleware
import "github.com/gin-gonic/gin"
func NoCacheMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Cache-Control", "no-cache, no-store, must-revalidate")
c.Header("Pragma", "no-cache")
c.Header("Expires", "0")
c.Next()
}
}

View File

@ -7,7 +7,6 @@ import (
func OptionsMiddleware() gin.HandlerFunc { func OptionsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
c.Set("disable_images", false) c.Set("disable_images", false)
c.Set("theme", "dark")
imagesCookie, err := c.Cookie("disable_images") imagesCookie, err := c.Cookie("disable_images")
if err == nil { if err == nil {
@ -16,13 +15,6 @@ func OptionsMiddleware() gin.HandlerFunc {
} }
} }
themeCookie, err := c.Cookie("theme")
if err == nil {
if themeCookie == "light" {
c.Set("theme", "light")
}
}
c.Next() c.Next()
} }
} }

View File

@ -47,7 +47,6 @@ func Ratelimit() gin.HandlerFunc {
if val.(int) > 30 { if val.(int) > 30 {
c.HTML(429, "home.html", gin.H{ c.HTML(429, "home.html", gin.H{
"errorMessage": "You have exceeded the request limit. Please try again in a minute.", "errorMessage": "You have exceeded the request limit. Please try again in a minute.",
"theme": c.MustGet("theme").(string),
"version": config.Version, "version": config.Version,
}) })
c.Abort() c.Abort()

View File

@ -12,7 +12,6 @@ import (
func GetHome(c *gin.Context) { func GetHome(c *gin.Context) {
c.HTML(200, "home.html", gin.H{ c.HTML(200, "home.html", gin.H{
"version": config.Version, "version": config.Version,
"theme": c.MustGet("theme").(string),
}) })
} }
@ -62,7 +61,6 @@ func PostHome(c *gin.Context) {
if err := c.ShouldBind(&body); err != nil { if err := c.ShouldBind(&body); err != nil {
c.HTML(400, "home.html", gin.H{ c.HTML(400, "home.html", gin.H{
"errorMessage": "Invalid request body", "errorMessage": "Invalid request body",
"theme": c.MustGet("theme").(string),
}) })
return return
} }
@ -72,7 +70,6 @@ func PostHome(c *gin.Context) {
if translated == "" { if translated == "" {
c.HTML(400, "home.html", gin.H{ c.HTML(400, "home.html", gin.H{
"errorMessage": "Invalid stack overflow/exchange URL", "errorMessage": "Invalid stack overflow/exchange URL",
"theme": c.MustGet("theme").(string),
}) })
return return
} }

View File

@ -3,8 +3,6 @@ package routes
import ( import (
"anonymousoverflow/config" "anonymousoverflow/config"
"fmt" "fmt"
"os"
"strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -21,26 +19,8 @@ func ChangeOptions(c *gin.Context) {
c.SetCookie("disable_images", fmt.Sprintf("%t", !c.MustGet("disable_images").(bool)), 60*60*24*365*10, "/", "", false, true) c.SetCookie("disable_images", fmt.Sprintf("%t", !c.MustGet("disable_images").(bool)), 60*60*24*365*10, "/", "", false, true)
c.HTML(200, "home.html", gin.H{ c.HTML(200, "home.html", gin.H{
"successMessage": "Images are now " + text, "successMessage": "Images are now " + text,
"theme": c.MustGet("theme").(string),
"version": config.Version, "version": config.Version,
}) })
case "theme":
text := "dark"
if c.MustGet("theme").(string) == "dark" {
text = "light"
}
c.SetCookie("theme", text, 60*60*24*365*10, "/", "", false, true)
// get redirect url from query
redirectUrl := c.Query("redirect_url")
if !strings.HasPrefix(redirectUrl, os.Getenv("APP_URL")) {
redirectUrl = os.Getenv("APP_URL")
}
c.Redirect(302, redirectUrl)
default: default:
c.String(400, "400 Bad Request") c.String(400, "400 Bad Request")
} }

View File

@ -34,7 +34,6 @@ func ViewQuestion(c *gin.Context) {
if _, err := strconv.Atoi(questionId); err != nil { if _, err := strconv.Atoi(questionId); err != nil {
c.HTML(400, "home.html", gin.H{ c.HTML(400, "home.html", gin.H{
"errorMessage": "Invalid question ID", "errorMessage": "Invalid question ID",
"theme": c.MustGet("theme").(string),
"version": config.Version, "version": config.Version,
}) })
return return
@ -60,7 +59,6 @@ func ViewQuestion(c *gin.Context) {
if resp.StatusCode() != 200 { if resp.StatusCode() != 200 {
c.HTML(500, "home.html", gin.H{ c.HTML(500, "home.html", gin.H{
"errorMessage": fmt.Sprintf("Received a non-OK status code %d", resp.StatusCode()), "errorMessage": fmt.Sprintf("Received a non-OK status code %d", resp.StatusCode()),
"theme": c.MustGet("theme").(string),
"version": config.Version, "version": config.Version,
}) })
return return
@ -74,7 +72,6 @@ func ViewQuestion(c *gin.Context) {
if err != nil { if err != nil {
c.HTML(500, "home.html", gin.H{ c.HTML(500, "home.html", gin.H{
"errorMessage": "Unable to parse question data", "errorMessage": "Unable to parse question data",
"theme": c.MustGet("theme").(string),
"version": config.Version, "version": config.Version,
}) })
return return
@ -84,7 +81,6 @@ func ViewQuestion(c *gin.Context) {
if err != nil { if err != nil {
c.HTML(500, "home.html", gin.H{ c.HTML(500, "home.html", gin.H{
"errorMessage": "Failed to extract question data", "errorMessage": "Failed to extract question data",
"theme": c.MustGet("theme").(string),
"version": config.Version, "version": config.Version,
}) })
return return
@ -94,7 +90,6 @@ func ViewQuestion(c *gin.Context) {
if err != nil { if err != nil {
c.HTML(500, "home.html", gin.H{ c.HTML(500, "home.html", gin.H{
"errorMessage": "Failed to extract answer data", "errorMessage": "Failed to extract answer data",
"theme": c.MustGet("theme").(string),
"version": config.Version, "version": config.Version,
}) })
return return
@ -110,7 +105,6 @@ func ViewQuestion(c *gin.Context) {
"question": newFilteredQuestion, "question": newFilteredQuestion,
"answers": answers, "answers": answers,
"imagePolicy": imagePolicy, "imagePolicy": imagePolicy,
"theme": c.MustGet("theme").(string),
"currentUrl": fmt.Sprintf("%s%s", os.Getenv("APP_URL"), c.Request.URL.Path), "currentUrl": fmt.Sprintf("%s%s", os.Getenv("APP_URL"), c.Request.URL.Path),
"sortValue": params.SoSortValue, "sortValue": params.SoSortValue,
"domain": domain, "domain": domain,
@ -132,7 +126,6 @@ func parseAndValidateParameters(c *gin.Context) (inputs viewQuestionInputs, err
if _, err = strconv.Atoi(questionId); err != nil { if _, err = strconv.Atoi(questionId); err != nil {
c.HTML(400, "home.html", gin.H{ c.HTML(400, "home.html", gin.H{
"errorMessage": "Invalid question ID", "errorMessage": "Invalid question ID",
"theme": c.MustGet("theme").(string),
"version": config.Version, "version": config.Version,
}) })
return return

View File

@ -33,7 +33,6 @@ func RedirectShortenedOverflowURL(c *gin.Context) {
if err != nil { if err != nil {
c.HTML(400, "home.html", gin.H{ c.HTML(400, "home.html", gin.H{
"errorMessage": "Unable to fetch stack overflow URL", "errorMessage": "Unable to fetch stack overflow URL",
"theme": c.MustGet("theme").(string),
}) })
return return
} }
@ -41,7 +40,6 @@ func RedirectShortenedOverflowURL(c *gin.Context) {
if resp.StatusCode() != 302 { if resp.StatusCode() != 302 {
c.HTML(400, "home.html", gin.H{ c.HTML(400, "home.html", gin.H{
"errorMessage": fmt.Sprintf("Unexpected HTTP status from origin: %d", resp.StatusCode()), "errorMessage": fmt.Sprintf("Unexpected HTTP status from origin: %d", resp.StatusCode()),
"theme": c.MustGet("theme").(string),
}) })
return return
} }

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html data-theme="{{ .theme }}"> <html>
<head> <head>
<title>AnonymousOverflow - Private frontend for StackOverflow</title> <title>AnonymousOverflow - Private frontend for StackOverflow</title>
@ -43,10 +43,9 @@
<div class="options"> <div class="options">
<div class="icon"> <div class="icon">
<a href="/options/images"> <a href="/options/images">
<img src="/static/icons/image.svg" alt="Toggle theme" /> <img src="/static/icons/image.svg" alt="Toggle images" />
</a> </a>
</div> </div>
{{ template "themeSwitcher.html" .}}
</div> </div>
<p class="footer"> <p class="footer">
Brought to you by Brought to you by

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html data-theme="{{ .theme }}"> <html>
<head> <head>
<title>{{ .question.Title }} | AnonymousOverflow</title> <title>{{ .question.Title }} | AnonymousOverflow</title>
@ -25,7 +25,6 @@
<a href="/" class="logo-link"> <a href="/" class="logo-link">
<img class="logo" src="/static/codecircles.webp" alt="AnonymousOverflow home" /> <img class="logo" src="/static/codecircles.webp" alt="AnonymousOverflow home" />
</a> </a>
{{ template "themeSwitcher.html" . }}
</div> </div>
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">

View File

@ -1,6 +0,0 @@
<div class="icon">
<a href="/options/theme?redirect_url={{ .currentUrl }}">
<img src="/static/icons/{{ if eq .theme "dark" }}sun{{
else }}moon{{ end }}.svg" alt="Toggle theme" />
</a>
</div>