dkforest

A forum and chat platform (onion)
git clone https://git.dasho.dev/n0tr1v/dkforest.git
Log | Files | Refs | LICENSE

commit 0d431a17ffd53f436d4a31e8ec8d5833b65c447b
parent 01a59f23c1f0b489fa77a4f72520fe6dc6d64a46
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Thu,  1 Jun 2023 04:11:19 -0700

odomoter css animation

Diffstat:
Apkg/odometer/odometer.go | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpkg/web/handlers/data.go | 5+++++
Mpkg/web/handlers/handlers.go | 7+++++++
Apkg/web/public/views/pages/odometer.gohtml | 18++++++++++++++++++
Mpkg/web/web.go | 1+
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)