commit 0d431a17ffd53f436d4a31e8ec8d5833b65c447b
parent 01a59f23c1f0b489fa77a4f72520fe6dc6d64a46
Author: n0tr1v <n0tr1v@protonmail.com>
Date: Thu, 1 Jun 2023 04:11:19 -0700
odomoter css animation
Diffstat:
5 files changed, 90 insertions(+), 0 deletions(-)
diff --git a/pkg/odometer/odometer.go b/pkg/odometer/odometer.go
@@ -0,0 +1,59 @@
+package odometer
+
+import (
+ "dkforest/pkg/utils"
+ "fmt"
+)
+
+type Odometer struct {
+ s string
+}
+
+func New(s string) *Odometer {
+ return &Odometer{s: s}
+}
+
+func (o *Odometer) Html() string {
+ out := `<div class="odometer">`
+ for i := 0; i < len(o.s); i++ {
+ out += fmt.Sprintf(`<div class="wrapper"><div class="outer"><span class="below odometer%d"></span><span class="top inner">%c</span></div></div>`, i, o.s[i])
+ }
+ out += "</div>"
+ return out
+}
+
+func (o *Odometer) Css() string {
+ out := `
+.odometer { display: table; font-family: monospace; font-size: 40px; }
+.odometer .wrapper { display: table-cell; }
+.odometer .outer { display: grid; grid-template: 1fr / 1fr; place-items: center; }
+.odometer .outer > * { grid-column: 1 / 1; grid-row: 1 / 1; }
+.odometer .outer .below { z-index: 1; }
+.odometer .outer .top { z-index: 2; }
+.odometer .outer .inner { visibility: visible; animation-name: inner_frames; animation-duration: 3s; }
+@keyframes inner_frames { 0% { visibility: hidden; } 99% { visibility: hidden; } 100% { visibility: visible; } }`
+ for i := 0; i < len(o.s); i++ {
+ out += fmt.Sprintf(`
+.odometer .odometer%d:before { visibility: hidden; content: "%c"; animation-name: odometer%d_frames; animation-duration: 3s; }
+@keyframes odometer%d_frames {`, i, o.s[i], i, i)
+ n := 20
+ step := 100.0 / float64(n)
+ pct := 0.0
+ out += ` 0% { visibility: visible; }`
+ for i := 0; i <= n; i++ {
+ if pct >= 99 {
+ break
+ }
+ if i == 0 {
+ pct += utils.RandFloat(0, 3)
+ }
+ num := utils.RandInt(0, 9)
+ out += fmt.Sprintf(`%.2f%% { content: "%d"; }`, pct, num)
+ pct += step
+ }
+ out += ` 99% { visibility: visible; }`
+ out += ` 100% { visibility: hidden; }`
+ out += `}`
+ }
+ return out
+}
diff --git a/pkg/web/handlers/data.go b/pkg/web/handlers/data.go
@@ -2,6 +2,7 @@ package handlers
import (
"dkforest/pkg/managers"
+ "dkforest/pkg/odometer"
v1 "dkforest/pkg/web/handlers/api/v1"
"time"
@@ -426,6 +427,10 @@ type chatCreateRoomData struct {
ErrCaptcha string
}
+type odometerData struct {
+ Odometer *odometer.Odometer
+}
+
type captchaData struct {
Ts int64
Seed int64
diff --git a/pkg/web/handlers/handlers.go b/pkg/web/handlers/handlers.go
@@ -7,6 +7,7 @@ import (
"crypto/sha256"
dutils "dkforest/pkg/database/utils"
"dkforest/pkg/hashset"
+ "dkforest/pkg/odometer"
"dkforest/pkg/pubsub"
"dkforest/pkg/utils/crypto"
v1 "dkforest/pkg/web/handlers/api/v1"
@@ -3911,6 +3912,12 @@ func CaptchaRequiredHandler(c echo.Context) error {
return c.Redirect(http.StatusFound, "/chat")
}
+func OdometerHandler(c echo.Context) error {
+ var data odometerData
+ data.Odometer = odometer.New("12345")
+ return c.Render(http.StatusOK, "odometer", data)
+}
+
func CaptchaHandler(c echo.Context) error {
var data captchaData
if c.QueryParam("a") != "" {
diff --git a/pkg/web/public/views/pages/odometer.gohtml b/pkg/web/public/views/pages/odometer.gohtml
@@ -0,0 +1,17 @@
+{{ define "extra-head" }}
+ <style>
+ {{ .Data.Odometer.Css | css }}
+ </style>
+{{ end }}
+
+{{ define "title" }}dkf - odometer{{ end }}
+
+{{ define "content" }}
+
+<div class="container">
+ <div class="col-8 offset-2 col-md-8 offset-md-2 col-sm-8 col-lg-6 offset-lg-3 col-xl-4 offset-xl-4">
+ {{ .Data.Odometer.Html | safe }}
+ </div>
+</div>
+
+{{ end }}
+\ No newline at end of file
diff --git a/pkg/web/web.go b/pkg/web/web.go
@@ -92,6 +92,7 @@ func getMainServer(db *database.DkfDB, i18nBundle *i18n.Bundle, renderer *tmp.Te
authGroup.GET("/public/img/signal/:signal/:data", handlers.SignalCss1)
authGroup.GET("/captcha-required", handlers.CaptchaRequiredHandler, middlewares.AuthRateLimitMiddleware(time.Second, 1))
authGroup.POST("/captcha-required", handlers.CaptchaRequiredHandler, middlewares.AuthRateLimitMiddleware(time.Second, 1))
+ authGroup.GET("/odometer", handlers.OdometerHandler, middlewares.AuthRateLimitMiddleware(time.Second, 1))
authGroup.GET("/captcha", handlers.CaptchaHandler, middlewares.AuthRateLimitMiddleware(time.Second, 1))
authGroup.POST("/captcha", handlers.CaptchaHandler, middlewares.AuthRateLimitMiddleware(time.Second, 1))
authGroup.GET("/donate", handlers.DonateHandler)