Loading static/css/yalikejazz.css +91 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ code { border-radius: 10px; box-shadow: 4px 2px 6px black; margin-top: 10px; overflow: hidden; } .card .title { Loading Loading @@ -67,6 +68,96 @@ code { .card .content { padding: 10px; position: relative; overflow: hidden; } .card .content .loader { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: none; justify-content: center; align-items: center; opacity: 0; flex-direction: column; color: #ffd533; } .card .content .loader .loader-bg { background-color: #334859; filter: blur(7px); opacity: .4; position: absolute; top: 0; left: 0; right: 0; bottom: 0; } .card .content .loader .loader-desc { z-index: 10; } .card .content .loader .loader-animation-wrapper { height: 2.4rem; position: relative; } .card .content .loader .loader-animation, .card .content .loader .loader-animation:before, .card .content .loader .loader-animation:after { background-color: #ffd533; display: block; width: .5rem; height: .7rem; border-radius: 50em; animation: escaleY 1s infinite ease-in-out; } .card .content .loader .loader-animation { position: relative; animation-delay: -0.16s; } .card .content .loader .loader-animation:before { content: ''; position: absolute; top: 0; left: -1.4rem; animation-delay: -0.32s; } .card .content .loader .loader-animation:after { content: ''; position: absolute; top: 0; left: 1.4rem; } @keyframes escaleY { 0%, 80%, 100% { box-shadow: 0 0; height: 1.8rem; } 40% { box-shadow: 0 -1em; height: 2.4rem; } } .card.verifying .content .loader { display: flex; transition: opacity .1s ease-in-out; opacity: 1; } .card.verifying .description, .card.verifying .actions { transition: filter .1s ease-in-out; filter: blur(1px); } .actions button, .actions a.btn { Loading static/js/exercises.api.mjs +16 −2 Original line number Diff line number Diff line Loading @@ -73,7 +73,16 @@ export class Exercise { /** * Set the handler that is called every time the exercise's completion * is verified (this verification might fail or be successful) * is in the process of being verified. * @param {Function} handler Function with no parameter */ onVerifiying(handler) { this.#context._verifyingHandler = handler } /** * Set the handler that is called every time the exercise's completion * is verified (this verification either failed or was successful) * @param {Function} handler Function that takes the result of the verification (true/false) as parameter */ onVerified(handler) { Loading Loading @@ -124,6 +133,7 @@ class ExerciseExecutionContext { constructor() { this._describeHandler = null this._verifyHandler = null this._verifyingHandler = null this._confirmExerciseCompletion = null } Loading Loading @@ -201,7 +211,10 @@ class ExerciseExecutionContext { */ manualConfirmation() { return new Promise((resolve, _) => { this._confirmExerciseCompletion = resolve this._confirmExerciseCompletion = () => { this._verifyingHandler() resolve() } }) } Loading Loading @@ -313,6 +326,7 @@ class ExerciseRetryExecutionContext extends ExerciseExecutionContext { super() this._describeHandler = oldContext._describeHandler this._verifyHandler = oldContext._verifyHandler this._verifyingHandler = oldContext._verifyingHandler } describe() {} Loading static/js/exercises.cards.mjs +25 −1 Original line number Diff line number Diff line Loading @@ -35,6 +35,22 @@ export function displayAsNonCurrent(cardEl) { } } /** * Changes the appearance of the given exercise card so it looks like it is currently being verified * @param {HTMLElement} cardEl The .card element */ export function displayAsVerifying(cardEl) { cardEl.classList.add("verifying") } /** * Changes the appearance of the given exercise card so it looks normal (no verification indicator) * @param {HTMLElement} cardEl The .card element */ export function displayAsNonVerifying(cardEl) { cardEl.classList.remove("verifying") } /** * Create a confirm and a reset button that can be appended to the actions section of * an exercise card. Loading Loading @@ -73,7 +89,15 @@ export function createExerciseCard(exercise, onTitleClick) { actionsEl.append(...createExerciseCardActionButtons( exercise.manuallyConfirm.bind(exercise) )) cardEl.querySelector(".content").append(descriptionEl, actionsEl) const loaderEl = createElementWithClass("div", "loader") loaderEl.innerHTML = ` <div class="loader-bg"></div> <div class="loader-animation-wrapper"> <span class="loader-animation"></span> </div> <span class="loader-desc">Deine Lösung wird überprüft...</span> ` cardEl.querySelector(".content").append(descriptionEl, actionsEl, loaderEl) // When the title bar of an exercise is clicked, skip to that exercise const titleEl = cardEl.querySelector(".title") Loading static/js/yalikejazz.mjs +3 −1 Original line number Diff line number Diff line import { State } from "./state.mjs" import * as tests from "./exercises.mjs" import { createExerciseCard, displayAsSolved, displayAsNonCurrent, displayAsCurrent } from "./exercises.cards.mjs" import { createExerciseCard, displayAsSolved, displayAsNonCurrent, displayAsCurrent, displayAsVerifying, displayAsNonVerifying } from "./exercises.cards.mjs" import { Exercise } from "./exercises.api.mjs" import { enableAutoFocus } from "./jslinux.api.mjs" Loading Loading @@ -44,8 +44,10 @@ function startExercise(exercise) { exercise.markAsCurrent(currentState) exercise.onDescribed((/** @type {string} */ description) => cardEl.querySelector(".description").textContent = description) exercise.onVerifiying(()=>displayAsVerifying(cardEl)) exercise.onVerified( (/** @type {boolean} */ success) => { displayAsNonVerifying(cardEl) if (success) { exercise.markAsSolved(currentState) displayAsSolved(cardEl) Loading Loading
static/css/yalikejazz.css +91 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ code { border-radius: 10px; box-shadow: 4px 2px 6px black; margin-top: 10px; overflow: hidden; } .card .title { Loading Loading @@ -67,6 +68,96 @@ code { .card .content { padding: 10px; position: relative; overflow: hidden; } .card .content .loader { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: none; justify-content: center; align-items: center; opacity: 0; flex-direction: column; color: #ffd533; } .card .content .loader .loader-bg { background-color: #334859; filter: blur(7px); opacity: .4; position: absolute; top: 0; left: 0; right: 0; bottom: 0; } .card .content .loader .loader-desc { z-index: 10; } .card .content .loader .loader-animation-wrapper { height: 2.4rem; position: relative; } .card .content .loader .loader-animation, .card .content .loader .loader-animation:before, .card .content .loader .loader-animation:after { background-color: #ffd533; display: block; width: .5rem; height: .7rem; border-radius: 50em; animation: escaleY 1s infinite ease-in-out; } .card .content .loader .loader-animation { position: relative; animation-delay: -0.16s; } .card .content .loader .loader-animation:before { content: ''; position: absolute; top: 0; left: -1.4rem; animation-delay: -0.32s; } .card .content .loader .loader-animation:after { content: ''; position: absolute; top: 0; left: 1.4rem; } @keyframes escaleY { 0%, 80%, 100% { box-shadow: 0 0; height: 1.8rem; } 40% { box-shadow: 0 -1em; height: 2.4rem; } } .card.verifying .content .loader { display: flex; transition: opacity .1s ease-in-out; opacity: 1; } .card.verifying .description, .card.verifying .actions { transition: filter .1s ease-in-out; filter: blur(1px); } .actions button, .actions a.btn { Loading
static/js/exercises.api.mjs +16 −2 Original line number Diff line number Diff line Loading @@ -73,7 +73,16 @@ export class Exercise { /** * Set the handler that is called every time the exercise's completion * is verified (this verification might fail or be successful) * is in the process of being verified. * @param {Function} handler Function with no parameter */ onVerifiying(handler) { this.#context._verifyingHandler = handler } /** * Set the handler that is called every time the exercise's completion * is verified (this verification either failed or was successful) * @param {Function} handler Function that takes the result of the verification (true/false) as parameter */ onVerified(handler) { Loading Loading @@ -124,6 +133,7 @@ class ExerciseExecutionContext { constructor() { this._describeHandler = null this._verifyHandler = null this._verifyingHandler = null this._confirmExerciseCompletion = null } Loading Loading @@ -201,7 +211,10 @@ class ExerciseExecutionContext { */ manualConfirmation() { return new Promise((resolve, _) => { this._confirmExerciseCompletion = resolve this._confirmExerciseCompletion = () => { this._verifyingHandler() resolve() } }) } Loading Loading @@ -313,6 +326,7 @@ class ExerciseRetryExecutionContext extends ExerciseExecutionContext { super() this._describeHandler = oldContext._describeHandler this._verifyHandler = oldContext._verifyHandler this._verifyingHandler = oldContext._verifyingHandler } describe() {} Loading
static/js/exercises.cards.mjs +25 −1 Original line number Diff line number Diff line Loading @@ -35,6 +35,22 @@ export function displayAsNonCurrent(cardEl) { } } /** * Changes the appearance of the given exercise card so it looks like it is currently being verified * @param {HTMLElement} cardEl The .card element */ export function displayAsVerifying(cardEl) { cardEl.classList.add("verifying") } /** * Changes the appearance of the given exercise card so it looks normal (no verification indicator) * @param {HTMLElement} cardEl The .card element */ export function displayAsNonVerifying(cardEl) { cardEl.classList.remove("verifying") } /** * Create a confirm and a reset button that can be appended to the actions section of * an exercise card. Loading Loading @@ -73,7 +89,15 @@ export function createExerciseCard(exercise, onTitleClick) { actionsEl.append(...createExerciseCardActionButtons( exercise.manuallyConfirm.bind(exercise) )) cardEl.querySelector(".content").append(descriptionEl, actionsEl) const loaderEl = createElementWithClass("div", "loader") loaderEl.innerHTML = ` <div class="loader-bg"></div> <div class="loader-animation-wrapper"> <span class="loader-animation"></span> </div> <span class="loader-desc">Deine Lösung wird überprüft...</span> ` cardEl.querySelector(".content").append(descriptionEl, actionsEl, loaderEl) // When the title bar of an exercise is clicked, skip to that exercise const titleEl = cardEl.querySelector(".title") Loading
static/js/yalikejazz.mjs +3 −1 Original line number Diff line number Diff line import { State } from "./state.mjs" import * as tests from "./exercises.mjs" import { createExerciseCard, displayAsSolved, displayAsNonCurrent, displayAsCurrent } from "./exercises.cards.mjs" import { createExerciseCard, displayAsSolved, displayAsNonCurrent, displayAsCurrent, displayAsVerifying, displayAsNonVerifying } from "./exercises.cards.mjs" import { Exercise } from "./exercises.api.mjs" import { enableAutoFocus } from "./jslinux.api.mjs" Loading Loading @@ -44,8 +44,10 @@ function startExercise(exercise) { exercise.markAsCurrent(currentState) exercise.onDescribed((/** @type {string} */ description) => cardEl.querySelector(".description").textContent = description) exercise.onVerifiying(()=>displayAsVerifying(cardEl)) exercise.onVerified( (/** @type {boolean} */ success) => { displayAsNonVerifying(cardEl) if (success) { exercise.markAsSolved(currentState) displayAsSolved(cardEl) Loading