diff --git a/_posts/2017-09-19-ops-s1-hello.markdown b/_posts/2017-09-19-ops-s1-hello.markdown index 34a8733..5a454ff 100644 --- a/_posts/2017-09-19-ops-s1-hello.markdown +++ b/_posts/2017-09-19-ops-s1-hello.markdown @@ -242,3 +242,7 @@ Which command lists your Docker images? - (x) docker image ls - ( ) docker run - ( ) docker container ls + +{:.quiz} +What command would you use to inspect "ubuntu" Docker image? +> docker image inspect ubuntu diff --git a/_posts/2017-09-19-ops-s1-swarm-intro.markdown b/_posts/2017-09-19-ops-s1-swarm-intro.markdown index 837f67a..dbcb20e 100644 --- a/_posts/2017-09-19-ops-s1-swarm-intro.markdown +++ b/_posts/2017-09-19-ops-s1-swarm-intro.markdown @@ -197,8 +197,8 @@ What is a stack? {:.quiz} A stack can: -- (x) be deployed from the commandline -- (x) use the compose file format to deploy -- ( ) run a Dockerfile -- ( ) be used to manage your hosts -- (x) be used to manage services over multiple nodes +- \[x] be deployed from the commandline +- \[x] use the compose file format to deploy +- \[ ] run a Dockerfile +- \[ ] be used to manage your hosts +- \[x] be used to manage services over multiple nodes diff --git a/_sass/_custom.scss b/_sass/_custom.scss index 39d03f6..e6cc059 100644 --- a/_sass/_custom.scss +++ b/_sass/_custom.scss @@ -1,3 +1,8 @@ +body { + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + font-size: 16px; +} + .panel-left .container { width: 100% !important; } diff --git a/css/quiz.css b/css/quiz.css index 26c0ff1..6302081 100644 --- a/css/quiz.css +++ b/css/quiz.css @@ -1,41 +1,161 @@ -/* Carousel base class */ -.carousel { - height: 500px; - margin-bottom: 60px; +:root { + --primary-color: #0083da; + --primary-highlight-color: #056fb6; + --primary-text-color: #000000; + --background-color: #ffffff; + --background-color2: #97cfec; + --second-bg-color: rgb(244, 244, 244); + --wrong-choice-color: red; + --wrong-choice-color2: rgb(255, 231, 231); + --correct-choice-color: green; + --correct-choice-color2: rgb(164, 238, 201); } -/* Since positioning the image, we need to help out the caption */ -.carousel-caption { - z-index: 10; + +:root[data-theme='dark'], +:root[data-force-color-mode="dark"] { + --primary-color: #4a6572; + --background-color: #eeeeee; + --second-bg-color: #dddddd; } -/* Declare heights because of positioning of img element */ -.carousel .item { - height: 500px; - background-color: #777; +body { + background-color: var(--background-color); + color: var(--primary-text-color); } -.carousel-inner > .item > img { - position: absolute; - top: 0; - left: 0; - min-width: 100%; - height: 500px; + +.quiz-title { + font-weight: 400; + font-size: 20px; + line-height: 22px; + margin: 10px 0px 5px 0px; } -.carousel-caption { - text-align: left; - top: 0%; +.quiz-question-content { + display: flex; + flex-flow: column; + gap: 10px; } -.carousel-caption label { - margin-bottom: 20px; - font-size: 21px; - line-height: 1; +.quiz-question-content.open-ended { + flex-flow: row; } -.quiz-success { - color: #5cb85c; +.quiz-question-content input.answer { + flex: 3 1 0%; + border: none; + border-radius: 4px; + padding: 10px; + background: var(--second-bg-color); } -.quiz-error { - color: #d9534f; +.quiz-question-content input.answer:focus { + border: none !important; } + +.quiz-question-content button.check { + border: none; + border-radius: 4px; + min-height: 30px; + background-color: var(--primary-color); + flex-grow: 1; + max-width: 40%; + cursor: pointer; + color: var(--background-color); + font-size: 14px; + font-weight: 600; +} + +.quiz-question-content button.check:hover { + background: var(--primary-highlight-color); +} + +.quiz-question-content button.check:active { + transform: translateY(1px); +} + +input[type="radio"], +input[type="checkbox"] { + font: inherit; + width: 1em; + height: 1em; + border: 0.15em solid currentColor; + border-radius: 0.15em; + transform: translateY(-0.075em); + place-content: center; + vertical-align: middle; + position: relative; + z-index: 1; + margin: 15px; + /* I am not happy with this solution, but putting checkbox inside of the + label, prevents checkbox:checked ~ .control-label from working. */ + margin-bottom: -45px; + display: none; +} + +input[type="checkbox"]:checked::before { + transform: scale(1); +} + +.control-label { + box-shadow: none; + font-size: 1em; + display: flex; + vertical-align: middle; + border: var(--second-bg-color) solid 1px; + border-radius: 4px; + background: var(--second-bg-color); + padding: 10px; + /* padding-left: 50px; */ + cursor: pointer; + font-weight: 400; +} + +.control-label:hover { + border: 1px solid var(--primary-color); + background: var(--background-color2); +} + +input[type="checkbox"]:checked~.control-label, +input[type="radio"]:checked~.control-label { + font-weight: 600; + transform: scale(1); + transition: 520ms transform ease-in-out; + border: 1px solid var(--primary-color); +} + +.no-select { + user-select: none; +} + +.post-content { + display: flex; + flex-direction: column; +} + +.font-medium { + font-weight: 500; +} + +.font-semibold { + font-weight: 600; +} + +.wrong-choice { + color: var(--wrong-choice-color); + background: var(--wrong-choice-color2); +} + +.correct-choice { + color: var(--correct-choice-color); + background: var(--correct-choice-color2); +} + +.chosen-choice { + border: currentColor solid 1px !important; + border-radius: 4px; +} + +.question-description { + color: gray; + font-size: 14px; +} \ No newline at end of file diff --git a/js/quiz.js b/js/quiz.js index 727bbb2..a200319 100644 --- a/js/quiz.js +++ b/js/quiz.js @@ -1,117 +1,110 @@ "use strict"; -addEventListener("load", () => { - let questions = {}; - const paragraphs = document.querySelectorAll('p.quiz'); +/** + * This script dynamically generates a quiz interface + * based on HTML markup generated from Markdown by Jekyll. + * + * Amount of possible choices is arbitrary. + * + * Usage: + * Markdown syntax for questions: + * For single-choice questions: + * Question + * - ( ) Wrong choice + * - (x) Correct choice + * - ( ) Wrong choice + * + * For multi-choice questions: + * Question + * - [ ] Wrong choice + * - [x] Correct choice + * - [x] Correct choice + * + * For open ended questions: + * Question + * > Expected answer + * + * Note: don't mix choice types, it will lead to parsing errors and choice will be ignored + * Note: validation results will be logged to the browser console. + */ + +// test +// document.documentElement.setAttribute('data-theme', 'dark'); +{ + let questions = []; + + function getQuestionContentId(questionIndex) { + return `question-${questionIndex}-content`; + } - if (paragraphs.length == 0) { - return; + // Case-insensitive string comparison. Returns true on match. + function strcmpi(a, b) { + return typeof a === 'string' && typeof b === 'string' + ? a.localeCompare(b, undefined, { sensitivity: 'accent' }) === 0 + : a === b; } - const carouselHTML = ` -
- `; - - document.querySelector('.post-content').insertAdjacentHTML('beforeend', carouselHTML); - - paragraphs.forEach((paragraph, index) => { - const options = paragraph.nextElementSibling; - - if (!options || options.tagName !== 'UL') { - return; + + function validateQuestion(event) { + const buttonElement = event.target; + const questionId = buttonElement.dataset.questionId; + const questionContextElement = document.getElementById(getQuestionContentId(questionId)); + const questionMetadata = questions[questionId]; + + const isOpenEnded = questionContextElement.classList.contains('open-ended'); + if (isOpenEnded) { + return validateQuestionWithAnswer(questionContextElement, questionMetadata); + } else { + return validateQuestionWithChoices(questionContextElement, questionMetadata); } + } - const question = paragraph.textContent; - paragraph.outerHTML = ` -