diff --git a/fontello-f6bebbfe.zip b/fontello-f6bebbfe.zip deleted file mode 100644 index dc92fbc..0000000 Binary files a/fontello-f6bebbfe.zip and /dev/null differ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..aa74511 --- /dev/null +++ b/go.mod @@ -0,0 +1,22 @@ +module lmika.dev/web/isknow + +go 1.24.4 + +require ( + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/gofiber/fiber/v2 v2.52.8 // indirect + github.com/gofiber/template v1.8.3 // indirect + github.com/gofiber/template/html/v2 v2.1.3 // indirect + github.com/gofiber/utils v1.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/sys v0.28.0 // indirect + lmika.dev/pkg/modash v0.0.0-20250619112300-0be0b6b35b1b // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..9049862 --- /dev/null +++ b/go.sum @@ -0,0 +1,37 @@ +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/gofiber/fiber/v2 v2.52.8 h1:xl4jJQ0BV5EJTA2aWiKw/VddRpHrKeZLF0QPUxqn0x4= +github.com/gofiber/fiber/v2 v2.52.8/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/gofiber/template v1.8.3 h1:hzHdvMwMo/T2kouz2pPCA0zGiLCeMnoGsQZBTSYgZxc= +github.com/gofiber/template v1.8.3/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8= +github.com/gofiber/template/html/v2 v2.1.3 h1:n1LYBtmr9C0V/k/3qBblXyMxV5B0o/gpb6dFLp8ea+o= +github.com/gofiber/template/html/v2 v2.1.3/go.mod h1:U5Fxgc5KpyujU9OqKzy6Kn6Qup6Tm7zdsISR+VpnHRE= +github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM= +github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +lmika.dev/pkg/modash v0.0.0-20250216001243-c73e50a0913d h1:x5aMBOkCr4cjJyFmq+qJVUsByfffD9k56HYDx1yZSR4= +lmika.dev/pkg/modash v0.0.0-20250216001243-c73e50a0913d/go.mod h1:8NDl/yR1eCCEhip9FJlVuMNXIeaztQ0Ks/tizExFcTI= +lmika.dev/pkg/modash v0.0.0-20250619112300-0be0b6b35b1b h1:Oymcj66pgyJ2CtGk9lPh06P4FOekllE1iPehDwaL0vw= +lmika.dev/pkg/modash v0.0.0-20250619112300-0be0b6b35b1b/go.mod h1:8NDl/yR1eCCEhip9FJlVuMNXIeaztQ0Ks/tizExFcTI= diff --git a/main.go b/main.go new file mode 100644 index 0000000..e08faf0 --- /dev/null +++ b/main.go @@ -0,0 +1,88 @@ +package main + +import ( + "fmt" + "log" + "net/http" + "os" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/template/html/v2" + "lmika.dev/web/isknow/models" +) + +func main() { + questions := models.QuestionSet{ + Questions: []models.Question{ + { + Text: "What is 1 + 1?", + Choices: []models.Choice{ + {Text: "1"}, + {Text: "2", IsRight: true}, + {Text: "3"}, + {Text: "4"}, + }, + Fact: "1 + 1 = 2", + }, + { + Text: "What is 3 * 5?", + Choices: []models.Choice{ + {Text: "5"}, + {Text: "10"}, + {Text: "15", IsRight: true}, + {Text: "20"}, + }, + Fact: "I can't use the iPad for coding this", + }, + }, + } + + prefix, _ := os.LookupEnv("PATH_PREFIX") + + engine := html.New("./views", ".html") + engine.AddFunc("prefix", func() string { return prefix }) + + app := fiber.New(fiber.Config{ + Views: engine, + ViewsLayout: "layout", + }) + + app.Get("/", func(c *fiber.Ctx) error { + return c.Render("index", fiber.Map{}) + }) + app.Get("/end", func(c *fiber.Ctx) error { + return c.Render("end", fiber.Map{}) + }) + app.Get("/:qid", func(c *fiber.Ctx) error { + qID, err := c.ParamsInt("qid") + if err != nil { + return c.SendStatus(http.StatusBadRequest) + } + + idx := qID - 1 + if idx < 0 || idx >= len(questions.Questions) { + return c.SendStatus(http.StatusBadRequest) + } + + rq, err := questions.Questions[idx].Render() + if err != nil { + return err + } + + nextURL := prefix + "/end" + reachedEnd := true + if idx+1 < len(questions.Questions) { + nextURL = fmt.Sprintf("%v/%d", prefix, idx+2) + reachedEnd = true + } + + return c.Render("question", fiber.Map{ + "q": rq, + "nextURL": nextURL, + "reachedEnd": reachedEnd, + }) + }) + app.Static("/assets", "./public") + + log.Fatal(app.Listen(":3000")) +} diff --git a/models/question.go b/models/question.go new file mode 100644 index 0000000..cab122a --- /dev/null +++ b/models/question.go @@ -0,0 +1,58 @@ +package models + +import ( + "errors" + "math/rand" + + "lmika.dev/pkg/modash/moslice" +) + +type QuestionSet struct { + Questions []Question +} + +type Choice struct { + Text string + IsRight bool +} + +type Question struct { + Text string + Choices []Choice + Fact string +} + +func (q Question) Render() (RenderedQuestion, error) { + choices := moslice.MapIndex(q.Choices, func(c Choice, i int) RenderedChoice { + return RenderedChoice{ + ID: i + 1, + Text: c.Text, + } + }) + rand.Shuffle(len(choices), func(i, j int) { + choices[i], choices[j] = choices[j], choices[i] + }) + _, idx, ok := moslice.FindWithIndexWhere(q.Choices, func(c Choice) bool { return c.IsRight }) + if !ok { + return RenderedQuestion{}, errors.New("question does not have a right answer") + } + + return RenderedQuestion{ + Question: q.Text, + Fact: q.Fact, + Choices: choices, + RightChoice: idx + 1, + }, nil +} + +type RenderedChoice struct { + ID int + Text string +} + +type RenderedQuestion struct { + Question string + Fact string + Choices []RenderedChoice + RightChoice int +} diff --git a/fontello/LICENSE.txt b/public/fontello/LICENSE.txt similarity index 100% rename from fontello/LICENSE.txt rename to public/fontello/LICENSE.txt diff --git a/fontello/README.txt b/public/fontello/README.txt similarity index 100% rename from fontello/README.txt rename to public/fontello/README.txt diff --git a/fontello/config.json b/public/fontello/config.json similarity index 100% rename from fontello/config.json rename to public/fontello/config.json diff --git a/fontello/css/animation.css b/public/fontello/css/animation.css similarity index 100% rename from fontello/css/animation.css rename to public/fontello/css/animation.css diff --git a/fontello/css/fontello-codes.css b/public/fontello/css/fontello-codes.css similarity index 100% rename from fontello/css/fontello-codes.css rename to public/fontello/css/fontello-codes.css diff --git a/fontello/css/fontello-embedded.css b/public/fontello/css/fontello-embedded.css similarity index 100% rename from fontello/css/fontello-embedded.css rename to public/fontello/css/fontello-embedded.css diff --git a/fontello/css/fontello-ie7-codes.css b/public/fontello/css/fontello-ie7-codes.css similarity index 100% rename from fontello/css/fontello-ie7-codes.css rename to public/fontello/css/fontello-ie7-codes.css diff --git a/fontello/css/fontello-ie7.css b/public/fontello/css/fontello-ie7.css similarity index 100% rename from fontello/css/fontello-ie7.css rename to public/fontello/css/fontello-ie7.css diff --git a/fontello/css/fontello.css b/public/fontello/css/fontello.css similarity index 100% rename from fontello/css/fontello.css rename to public/fontello/css/fontello.css diff --git a/fontello/demo.html b/public/fontello/demo.html similarity index 100% rename from fontello/demo.html rename to public/fontello/demo.html diff --git a/fontello/font/fontello.eot b/public/fontello/font/fontello.eot similarity index 100% rename from fontello/font/fontello.eot rename to public/fontello/font/fontello.eot diff --git a/fontello/font/fontello.svg b/public/fontello/font/fontello.svg similarity index 100% rename from fontello/font/fontello.svg rename to public/fontello/font/fontello.svg diff --git a/fontello/font/fontello.ttf b/public/fontello/font/fontello.ttf similarity index 100% rename from fontello/font/fontello.ttf rename to public/fontello/font/fontello.ttf diff --git a/fontello/font/fontello.woff b/public/fontello/font/fontello.woff similarity index 100% rename from fontello/font/fontello.woff rename to public/fontello/font/fontello.woff diff --git a/fontello/font/fontello.woff2 b/public/fontello/font/fontello.woff2 similarity index 100% rename from fontello/font/fontello.woff2 rename to public/fontello/font/fontello.woff2 diff --git a/index.html b/public/index.html similarity index 100% rename from index.html rename to public/index.html diff --git a/scripts/controllers/picker.js b/public/scripts/controllers/picker.js similarity index 85% rename from scripts/controllers/picker.js rename to public/scripts/controllers/picker.js index 17e32ee..ba86c7b 100644 --- a/scripts/controllers/picker.js +++ b/public/scripts/controllers/picker.js @@ -1,7 +1,7 @@ import { Controller } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.js"; export default class extends Controller { - static targets = [ "radio" ]; + static targets = ["radio", "answerDetails"]; static values = { answer: String @@ -25,5 +25,7 @@ export default class extends Controller { } }); }, 1); + + this.answerDetailsTarget.classList.remove("hidden"); } }; \ No newline at end of file diff --git a/scripts/main.js b/public/scripts/main.js similarity index 100% rename from scripts/main.js rename to public/scripts/main.js diff --git a/style.css b/public/style.css similarity index 73% rename from style.css rename to public/style.css index a9cdc70..59cd86c 100644 --- a/style.css +++ b/public/style.css @@ -78,4 +78,45 @@ input[type=radio] { padding: 0; margin: 0; margin-inline-start: -1px; +} + +.hidden { + display: none !important; +} + +/** + * Page transition + */ +@view-transition { + navigation: auto; +} + + +@keyframes move-out { + from { + transform: translateX(0%); + } + + to { + transform: translateX(-100%); + } +} + +@keyframes move-in { + from { + transform: translateX(100%); + } + + to { + transform: translateX(0%); + } +} + +/* Apply the custom animation to the old and new page states */ +::view-transition-old(root) { + animation: 0.3s ease-in both move-out; +} + +::view-transition-new(root) { + animation: 0.3s ease-in both move-in; } \ No newline at end of file diff --git a/views/end.html b/views/end.html new file mode 100644 index 0000000..ea4de5e --- /dev/null +++ b/views/end.html @@ -0,0 +1,3 @@ +

Well Done

+ +

You reached the end

diff --git a/views/index.html b/views/index.html new file mode 100644 index 0000000..ed27459 --- /dev/null +++ b/views/index.html @@ -0,0 +1,5 @@ +

Welcome

+ +

Welcome to the quiz

+ +Lets go \ No newline at end of file diff --git a/views/layout.html b/views/layout.html new file mode 100644 index 0000000..9d05c07 --- /dev/null +++ b/views/layout.html @@ -0,0 +1,14 @@ + + + + + + + + + + + {{embed}} + + + \ No newline at end of file diff --git a/views/question.html b/views/question.html new file mode 100644 index 0000000..14b3bd4 --- /dev/null +++ b/views/question.html @@ -0,0 +1,31 @@ +
+ + +
+ +
+

{{.q.Question}}

+ + {{range .q.Choices}} + + {{end}} + + + + +
+ + \ No newline at end of file