From 0b200174087a002ee92a48d31b9d38551a937387 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Mon, 23 Jun 2025 13:50:50 +0200 Subject: [PATCH] Finished the remaining screens I think it's good to ship --- main.go | 13 ++++++-- public/scripts/controllers/gamestate.js | 21 +++++++++++++ public/scripts/controllers/picker.js | 20 +++++++++---- public/scripts/controllers/yourscore.js | 14 +++++---- public/style.css | 40 +++++++++++++++++++++++-- views/end.html | 17 +++++++++++ views/index.html | 31 ++++++++++--------- views/layout.html | 2 +- views/question.html | 23 ++++++++++---- views/results.html | 4 ++- 10 files changed, 146 insertions(+), 39 deletions(-) create mode 100644 views/end.html diff --git a/main.go b/main.go index d93d254..9d5ee0a 100644 --- a/main.go +++ b/main.go @@ -35,16 +35,23 @@ func main() { }) app := fiber.New(fiber.Config{ - Views: engine, - ViewsLayout: "layout", + Views: engine, + ViewsLayout: "layout", + PassLocalsToViews: true, }) app.Get("/", func(c *fiber.Ctx) error { + c.Locals("fadeIn", true) return c.Render("index", fiber.Map{}) }) app.Get("/results", func(c *fiber.Ctx) error { + c.Locals("fadeIn", true) return c.Render("results", fiber.Map{}) }) + app.Get("/end", func(c *fiber.Ctx) error { + c.Locals("fadeIn", true) + return c.Render("end", fiber.Map{}) + }) app.Get("/:qid", func(c *fiber.Ctx) error { qID, err := c.ParamsInt("qid") if err != nil { @@ -68,8 +75,10 @@ func main() { reachedEnd = true } + c.Locals("fadeIn", idx == 0) return c.Render("question", fiber.Map{ "q": rq, + "qIdx": qID, "nextURL": nextURL, "reachedEnd": reachedEnd, }) diff --git a/public/scripts/controllers/gamestate.js b/public/scripts/controllers/gamestate.js index 1a5ed86..bb496a7 100644 --- a/public/scripts/controllers/gamestate.js +++ b/public/scripts/controllers/gamestate.js @@ -1,4 +1,5 @@ const GAME_STATE_KEY = "gameState"; +const MAX_QUESTIONS = 10; class GameState { getQuestionChoice(qId) { @@ -19,6 +20,10 @@ class GameState { localStorage.removeItem(GAME_STATE_KEY); } + getMaxQuestions() { + return MAX_QUESTIONS; + } + getSummary() { let savedItem = this._readGameState(); let summary = { totalAnswered: 0, totalRight: 0 }; @@ -30,6 +35,22 @@ class GameState { } } + if (summary.totalAnswered != MAX_QUESTIONS) { + summary.rank = "Incompletionist"; + } else if (summary.totalRight <= 2) { + summary.rank = "Developer"; + } else if (summary.totalRight <= 5) { + summary.rank = "Senior Developer"; + } else if (summary.totalRight <= 7) { + summary.rank = "Standard Enthusiast"; + } else if (summary.totalRight <= 9) { + summary.rank = "Standard Maker"; + } else if (summary.totalRight == 10) { + summary.rank = "ISO President"; + } else { + summary.rank = "Beta Tester"; + } + return summary; } diff --git a/public/scripts/controllers/picker.js b/public/scripts/controllers/picker.js index c5d8a6a..06e281f 100644 --- a/public/scripts/controllers/picker.js +++ b/public/scripts/controllers/picker.js @@ -2,7 +2,7 @@ import { Controller } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.j import { gameState } from "./gamestate.js"; export default class extends Controller { - static targets = ["radio", "answerDetails", "submit"]; + static targets = ["radio", "submitButton", "answerDetails", "submit", "result"]; static values = { qid: String, @@ -12,7 +12,7 @@ export default class extends Controller { connect() { let hasAnswer = gameState.getQuestionChoice(this.qidValue); if (hasAnswer) { - this._revealAnswer(); + this._revealAnswer(hasAnswer.isRight); let e = this.radioTargets.find((e) => e.value == hasAnswer.cId); if (e) { @@ -35,24 +35,32 @@ export default class extends Controller { return; } - gameState.setQuestionChoice(this.qidValue, e.value, e.value === this.answerValue); + let wasRight = e.value === this.answerValue; + gameState.setQuestionChoice(this.qidValue, e.value, wasRight); this.element.classList.add("reveal"); - window.setTimeout(() => { this._revealAnswer(); }); + window.setTimeout(() => { this._revealAnswer(wasRight); }); } - _revealAnswer() { + _revealAnswer(wasRight) { this.element.classList.add("reveal"); this.radioTargets.forEach(e => { e.disabled = true; if (e.value === this.answerValue) { - e.classList.add("answer"); + e.classList.add("answer"); } else { e.classList.add("wrong"); } }); + if (wasRight) { + this.resultTarget.innerText = "Correct"; + } else { + this.resultTarget.innerText = "Sorry, that's incorrect"; + } + + this.submitButtonTarget.classList.add("hidden"); this.answerDetailsTarget.classList.remove("hidden"); } }; \ No newline at end of file diff --git a/public/scripts/controllers/yourscore.js b/public/scripts/controllers/yourscore.js index 9f756b9..4ae6a5a 100644 --- a/public/scripts/controllers/yourscore.js +++ b/public/scripts/controllers/yourscore.js @@ -2,7 +2,6 @@ import { Controller } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.j import { gameState } from "./gamestate.js"; const ANIMATION_DURATION = 1500.0; -const MAX_QUESTIONS = 10; const CIRCLE_RADIUS = 50; export default class extends Controller { @@ -11,14 +10,16 @@ export default class extends Controller { connect() { this._startT = 0; - requestAnimationFrame(this._startAnimating.bind(this)); + window.setTimeout(() => { + requestAnimationFrame(this._startAnimating.bind(this)); + }, 500); } _startAnimating(t) { this._finalScore = gameState.getSummary().totalRight; this._startT = t; - this._finalArcPostition = 360 * this._finalScore / MAX_QUESTIONS; + this._finalArcPostition = 360 * this._finalScore / gameState.getMaxQuestions(); this._currentlyDisplayedScore = 0; this.countTarget.innerText = "0%"; @@ -36,7 +37,7 @@ export default class extends Controller { this.pathTarget.setAttribute("d", this._describeArc(CIRCLE_RADIUS, CIRCLE_RADIUS, CIRCLE_RADIUS - 5, 0, this._finalArcPostition)); } - let scoreToDisplay = (this._finalScore * 100 / MAX_QUESTIONS) | 0; + let scoreToDisplay = (this._finalScore * 100 / gameState.getMaxQuestions()) | 0; this.countTarget.innerText = `${scoreToDisplay}%`; window.setTimeout(() => this._showPostStore(), 1); return; @@ -46,7 +47,7 @@ export default class extends Controller { this.pathTarget.setAttribute("d", this._describeArc(CIRCLE_RADIUS, CIRCLE_RADIUS, CIRCLE_RADIUS - 5, 0, this._finalArcPostition * arcT)); - let scoreToDisplay = (arcT * this._finalScore * 100 / MAX_QUESTIONS) | 0; + let scoreToDisplay = (arcT * this._finalScore * 100 / gameState.getMaxQuestions()) | 0; if (scoreToDisplay != this._currentlyDisplayedScore) { this._currentlyDisplayedScore = scoreToDisplay; this.countTarget.innerText = `${scoreToDisplay}%`; @@ -90,7 +91,8 @@ export default class extends Controller { } _showPostStore() { - this.rankTarget.innerText = "Developer"; + let rank = gameState.getSummary().rank; + this.rankTarget.innerText = rank; this.postScoreTarget.classList.remove("hidden"); } diff --git a/public/style.css b/public/style.css index ff9a432..e37d69c 100644 --- a/public/style.css +++ b/public/style.css @@ -2,10 +2,32 @@ --score-color: green; } +div.center-prose { + max-width: 60vh; + margin-inline: auto; +} + div.offscreen { - position: fixed; - left: -100px; - top: -100px; + position: fixed; + left: -100px; + top: -100px; +} + +div.center-align { + text-align: center; +} + +img.logo { + display: inline-block; + width: 60vh; + height: auto; +} + +/*** + * Question + */ +.submit-and-answer { + margin-block-start: 1.5em; } div.question.reveal label { @@ -93,6 +115,10 @@ input[type=radio] { height: 2em; } +h4 { + margin-bottom: 0.8rem; +} + /** * Your score */ @@ -206,6 +232,14 @@ div.rank { animation: 0.3s ease-in both move-in; } +:root.fade-transition::view-transition-old(root) { + animation: 0.3s ease-in both fade-out; +} + +:root.fade-transition::view-transition-new(root) { + animation: 0.3s ease-in both fade-in; +} + @media (prefers-reduced-motion: reduce) { ::view-transition-old(root) { animation: 0.3s ease-in both fade-out; diff --git a/views/end.html b/views/end.html new file mode 100644 index 0000000..0eef9ef --- /dev/null +++ b/views/end.html @@ -0,0 +1,17 @@ +
+ +
+ +
+

The End

+
+ +
+

Thank you for playing this quiz.

+

I hope you enjoyed this, or at the very least, I hope it wasn't too hard.

+

Leon Mika, 2025

+
+ +
+ Return to Home +
\ No newline at end of file diff --git a/views/index.html b/views/index.html index 79c582d..e83c016 100644 --- a/views/index.html +++ b/views/index.html @@ -1,16 +1,19 @@ -I.S. Know logo, featuring a wireframe sphere instead of an O - -
-

Greetings fellow web developer,

-

I'm sure you deal with ISO and RFC standards all the time as part of your work, but how well do you - actually know them? Take this quiz of 10 questions to test your knowledge of standards - common to web and server development and prove to anyone who cares to listen that you too are an - I.S. Knowlable person.

-

Just know that this is for amusement purposes only and any knowledge you might gain is - purely coincidental. -

-

Good luck,

-

— lmika

+
+
-Begin \ No newline at end of file +
+

Greetings fellow developer,

+

You deal with ISO and RFC standards all the time as part of your work, but how well do you + know them? Take this quiz of 10 questions to test your knowledge of standards + common to web and server development and prove to anyone who cares to listen that you too are an + I.S. Knowlable person.

+

This is for amusement purposes only and any knowledge you might gain is + purely coincidental. +

+

Good luck.

+
+ +
+ Begin +
\ No newline at end of file diff --git a/views/layout.html b/views/layout.html index 5fb9d87..94e5114 100644 --- a/views/layout.html +++ b/views/layout.html @@ -1,5 +1,5 @@ - + diff --git a/views/question.html b/views/question.html index 3db784d..7c6d646 100644 --- a/views/question.html +++ b/views/question.html @@ -5,6 +5,11 @@
+ +
+

Question {{.qIdx}}

+
+

{{.q.Question}}

{{range .q.Choices}} @@ -19,12 +24,18 @@ {{end}} - - -