Commit f3de9c5e authored by Vlad Dumitru's avatar Vlad Dumitru
Browse files

niceify stuff

parent 06dede44
Pipeline #6691 failed with stages
in 2 minutes and 22 seconds
......@@ -5,10 +5,10 @@
{% for question in quiz.questions %}
<div class="question">
<div class="text">{{ question.text }}</div>
<a href="/quiz/{{ quiz.id }}/question/{{ question.id }}">
<a class="interactive" href="/quiz/{{ quiz.id }}/question/{{ question.id }}">
<img src="/img/{{ question.image }}">
</a>
<a href="/quiz/{{ quiz.id }}/results/{{ question.id }}">Ergebnisse</a>
<a class="text" href="/quiz/{{ quiz.id }}/question/{{ question.id }}/results">Ergebnisse</a>
</div>
{% endfor %}
</div>
......
{% extends "base.html" %}
{% block content %}
<div class="screen">
<div class="question-container">
<h2>{{ question.text }}</h2>
{% if question.media.type = "video" %}
......@@ -26,14 +27,37 @@
</div>
{% endif %}
{% if question.type = "free-form" %}
<input name="choice" type="text">
<input id="text-input" name="choice" type="text">
{% endif %}
<input type="submit" value="submit">
<input id="submit" type="submit" value="✓" disabled>
</form>
</div>
</div>
{% endblock %}
{% block page-scripts %}
<script>
window.addEventListener('load', () => {
const submitButton = document.getElementById('submit')
const enableSubmit = () => { submitButton.disabled = false }
const disableSubmit = () => { submitButton.disabled = true }
{% if question.type = "multiple-choice" %}
Array.from(document.getElementsByTagName('input'))
.forEach(element => element.addEventListener('change', enableSubmit))
{% endif %}
{% if question.type = "free-form" %}
const textInput = document.getElementById('text-input')
textInput.addEventListener('input', () => {
if (textInput.value.trim() !== '')
enableSubmit()
else
disableSubmit()
})
{% endif %}
})
</script>
{% if question.media.type = "audio" %}
<script>
window.addEventListener('load', () => {
......
{% extends "base.html" %}
{% block content %}
<div class="container">
<ul class="box">
{% for recording in recordings %}
<li>
<strong>{{ recording.description }}</strong>
<audio src="/record/data/{{ recording.id }}" controls>
</li>
<div class="question">
<div class="text">{{ recording.description }}</div>
<a class="interactive" data-audio-target="audio-{{ recording.id }}">
<img src="/img/headphones.jpg">
</a>
<audio id="audio-{{ recording.id }}" src="/record/data/{{ recording.id }}"></audio>
</div>
{% endfor %}
</ul>
</div>
{% endblock %}
{% block page-scripts %}
<script>
window.addEventListener('load', () => {
Array.from(document.querySelectorAll('a.interactive'))
.forEach(element => element.addEventListener('click', () =>
document.getElementById(element.dataset['audioTarget']).play()))
})
</script>
{% endblock %}
{% extends "base.html" %}
{% block content %}
<audio id="audio"></audio>
<div class="container flex col" id="recorder">
<div class="box flex col">
<h2>
Schreibe die Sprache deines Zungenbrechers auf:
</h2>
<input type="text" name="language">
</div>
<div class="box flex col">
<h2>
Drücke die Aufnahmetaste und spreche in das Mikrofon.
</h2>
<div class="flex row align-center justify-center">
<canvas id="waveform-canvas"></canvas>
</div>
<div class="flex row justify-center">
<button id="toggle-record-button" class="spinning">
<img src="/img/Mikrophon.jpeg">
</button>
<div class="screen">
<div class="box flex col" style="width: 75%;">
<h2>
Schreibe die Sprache deines Zungenbrechers auf:
</h2>
<input type="text" name="language">
</div>
<div class="flex row">
<div id="sound-clips-container"></div>
</div>
<div class="screen">
<div class="box flex col" style="width: 85%;">
<h2>
Drücke die Aufnahmetaste und sprich in das Mikrofon.
</h2>
<div class="flex row align-center justify-center">
<canvas id="waveform-canvas"></canvas>
</div>
<div class="flex row justify-space-around">
<button id="toggle-record-button" class="spinning">
<img src="/img/Mikrophon.jpeg">
</button>
<button id="toggle-play-button" disabled>
<img src="/img/headphones.jpg">
</button>
<button id="upload-button" disabled>
<img src="/img/mix.jpg">
</button>
</div>
<div class="flex row">
<div id="sound-clips-container"></div>
</div>
</div>
</div>
</div>
......@@ -29,12 +40,14 @@
{% block page-scripts %}
<script>
const CANVAS_WIDTH = 500
const CANVAS_HEIGHT = 250
const CANVAS_WIDTH = 512
const CANVAS_HEIGHT = 128
const gotStream = stream => {
const toggleRecordButton = document.getElementById('toggle-record-button')
const soundClipsContainer = document.getElementById('sound-clips-container')
const audioElement = document.getElementById('audio')
const toggleRecordButton = document.getElementById('toggle-record-button')
const togglePlayButton = document.getElementById('toggle-play-button')
const uploadButton = document.getElementById('upload-button')
const mediaRecorder = new MediaRecorder(stream)
......@@ -102,48 +115,40 @@
}
})
togglePlayButton.addEventListener('click', () => {
audioElement.play()
})
const uploadHandler = () => {
if (window.recording === undefined) return
const formData = new FormData()
formData.append('file', window.recording)
formData.append('lang', document.getElementsByName('language')[0].value)
fetch('record', { method: 'POST', body: formData })
.then(res => window.location = res.url)
.catch(err => console.error(err))
}
uploadButton.addEventListener('click', uploadHandler)
mediaRecorder.addEventListener('dataavailable', e =>
chunks.push(e.data))
mediaRecorder.addEventListener('stop', e => {
const clipContainer = document.createElement('div')
const clipLabel = document.createElement('span')
const audioElement = document.createElement('audio')
const deleteButton = document.createElement('button')
const uploadButton = document.createElement('button')
clipContainer.classList.add('audio-clip')
audioElement.setAttribute('controls', '')
deleteButton.innerHTML = 'delete'
uploadButton.innerHTML = 'upload'
clipLabel.innerHTML = 'audio clip'
clipContainer.appendChild(audioElement)
clipContainer.appendChild(clipLabel)
clipContainer.appendChild(deleteButton)
clipContainer.appendChild(uploadButton)
soundClipsContainer.appendChild(clipContainer)
const blob = new Blob(chunks, { type: mediaRecorder.mimeType })
console.log(`${chunks.length} chunks were saved`)
chunks = []
const audioURL = window.URL.createObjectURL(blob)
audioElement.src = audioURL
deleteButton.addEventListener('click', e => {
let eventTarget = e.target
eventTarget.parentNode.parentNode.removeChild(eventTarget.parentNode)
})
/* dirty stuff */
window.recording = blob
uploadButton.addEventListener('click', () => {
const formData = new FormData()
formData.append('file', blob)
formData.append('lang', document.getElementsByName('language')[0].value)
togglePlayButton.disabled = false
uploadButton.disabled = false
fetch('record', { method: 'POST', body: formData })
.then(res => window.location = res.url)
.catch(err => console.error(err))
})
})
}
......
......@@ -31,6 +31,7 @@ body {
.flex.align-center { align-items: center; }
.flex.justify-center { justify-content: center; }
.flex.justify-space-around { justify-content: space-around; }
.font-a { font-family: 'Our Daydream', sans-serif; }
.font-b { font-family: 'Rampart One', sans-serif; }
......@@ -38,13 +39,14 @@ body {
.box {
background: rgba(255, 255, 255, 0.85);
border-radius: 0.25rem;
padding: 0.5rem 1rem;
padding: 1rem 2rem;
}
h2 {
margin: 0;
font-family: 'Our Daydream';
font-size: 2rem;
text-align: center;
}
header {
......@@ -127,6 +129,9 @@ header > .lhs > img {
form {
display: flex;
flex-flow: row nowrap;
justify-content: space-around;
width: 75%;
}
......@@ -141,9 +146,10 @@ main {
margin-left: 8rem;
}
button, a.interactive {
button, a.interactive, #submit {
border-radius: 50%;
min-width: 5rem;
width: 8rem;
height: 8rem;
border: none;
background-color: rgba(0, 0, 128, 0.25);
color: white;
......@@ -151,12 +157,19 @@ button, a.interactive {
transition: ease-in-out all 0.25s;
}
#submit {
font-family: sans-serif;
position: absolute;
right: 6vw;
top: 47.5vh;
font-size: 6rem;
}
a.interactive {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
height: 5rem;
text-decoration: none;
font-size: 4rem;
......@@ -164,10 +177,15 @@ a.interactive {
button > img {
border-radius: 50%;
align-self: flex-start;
width: 100%;
height: 100%;
}
button:disabled > img {
opacity: 25%;
}
button:not(:disabled):hover, a.interactive:hover {
button:not(:disabled):hover, a.interactive:hover, #submit:not(:disabled):hover {
transform: scale(1.25);
background-color: rgba(0, 0, 128, 0.5);
}
......@@ -178,7 +196,7 @@ button.scroller {
font-size: 4rem;
}
button.scroller:disabled {
button.scroller:disabled, #submit:disabled {
color: rgba(255, 255, 255, 0.1);
background-color: rgba(0, 0, 0, 0.1);
}
......@@ -192,7 +210,6 @@ button.scroller:disabled {
}
#go-back {
height: 5rem;
position: absolute;
top: 50vh;
left: 2vw;
......@@ -261,7 +278,7 @@ button.scroller:disabled {
transition: ease-in-out transform 0.25s;
}
.in-circle { position: absolute; top: 50%; left: max(50vh, 50vw); margin: -2.5rem -10rem; }
.in-circle { position: absolute; top: 50vh; left: 50vw; margin: -5vh -5rem; }
.in-circle:nth-of-type(1) { transform: rotate(72deg) translate(10rem) rotate(-72deg); }
.in-circle:nth-of-type(2) { transform: rotate(144deg) translate(10rem) rotate(-144deg); }
......@@ -279,7 +296,7 @@ button.scroller:disabled {
align-items: center;
margin: 5.5rem auto 0.5rem auto;
max-width: 40rem;
max-width: 50vw;
}
.question {
......@@ -306,20 +323,13 @@ button.scroller:disabled {
border: 1px solid #000;
}
.question > a {
width: 100%;
border-bottom: 0.125rem dashed rgba(0, 0, 0, 0.05);
}
.question > .text {
.question > div.text {
flex-basis: 33%;
flex-shrink: 0;
display: flex;
flex-flow: column nowrap;
justify-content: center;
border-bottom: 0.125rem solid rgba(255, 255, 255, 0.8);
}
.sticky-title {
......@@ -382,3 +392,48 @@ video {
margin: 1rem 0;
max-width: 75%;
}
.screen {
height: 80vh;
margin-top: calc(5vh + 1rem);
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
}
input[type="text"] {
font: inherit;
font-size: 1.5rem;
margin: 0.5rem 0;
transition: 0.25s all;
border-radius: 0.125rem;
padding: 0.5rem 1rem;
border: 0.125rem solid rgba(32, 32, 32, 0.2);
}
input[type="text"]:focus {
transform: scale(1.25);
}
a.text {
text-decoration: none;
color: blue;
transition: 0.25s all;
}
a.text:hover {
transform: scale(1.25);
text-shadow:
1px 0px #fff, -1px 0px #fff, 0px 1px #fff, 0px -1px #fff,
1px -1px #fff, -1px 1px #fff, 1px 1px #fff, -1px -1px #fff,
0px 0px 1rem #fff;
}
a.text::before {
content: '((( ';
}
a.text::after {
content: ' )))';
}
......@@ -4,7 +4,7 @@
"questions": [
{
"type": "multiple-choice",
"text": "Hör Genau Hin, mache dabei die Augen zu! Was hörst du?",
"text": "Hör genau hin, mache dabei die Augen zu! Was hörst du?",
"image": "cucumber.jpg",
"choices": [ "DADA", "DATA", "TADA", "BABA" ],
"media": {
......@@ -14,7 +14,7 @@
},
{
"type": "multiple-choice",
"text": "Hör Genau Hin, und schaue den Jungen dabei gut zu! Was hörst du?",
"text": "Hör genau hin, und schaue dem Jungen dabei gut zu! Was hörst du?",
"image": "cucumber.jpg",
"choices": [ "DADA", "DATA", "TADA", "BABA" ],
"media": {
......
......@@ -36,8 +36,9 @@
:question_id (:id question)
:value value}))
(defn answers-for [question-id]
(jdbc/query db ["select * from answer where question_id = ?" question-id]))
(defn answers-for [quiz question]
(jdbc/query db ["select * from answer where quiz_id = ? and question_id = ?"
(:id quiz) (:id question)]))
(defn save-recording! [description file]
(jdbc/insert! db :recording {:description description, :data file}))
......
......@@ -17,10 +17,25 @@
(defn about-page [request]
(layout/render request "about.html"))
(defn- assoc-answers-to-question [quiz question]
(prn question)
(let [answers (db/answers-for quiz question)
results (->> (map :value answers) frequencies)]
(assoc question :results results)))
(defn- assoc-answers-to-quiz [[id quiz]]
[id (assoc quiz :questions
(map #(assoc-answers-to-question quiz %) (:questions quiz)))])
(defn render-breakdown [request]
{:status 200
:body (into {} (map assoc-answers-to-quiz quiz/quizzes))})
(defn home-routes []
[""
{:middleware [middleware/wrap-csrf
middleware/wrap-formats]}
["/" {:get home-page}]
["/about" {:get about-page}]])
["/about" {:get about-page}]
["/breakdown" {:get render-breakdown}]])
......@@ -15,7 +15,9 @@
(defn- render-question-list [quiz]
(fn [request]
(layout/render request "quiz/question-list.html"
{:quiz quiz :backlink "/"})))
{:title (:title quiz)
:quiz quiz
:backlink "/"})))
(defn- render-question [quiz question]
(fn [request]
......@@ -37,10 +39,10 @@
:body "unacceptable answer"}))
(defn- answer-free-form-question [quiz question answer]
(db/answer! (:id question) answer)
(db/answer! quiz question answer)
{:status 301
:headers {"Location"
(str "/quiz/" (:id quiz) "/results/" (:id question))}})
(str "/quiz/" (:id quiz) "/question/" (:id question) "/results")}})
(defn- answer-question [quiz question]
(fn [request]
......@@ -54,7 +56,7 @@
(defn- render-question-results [quiz question]
(fn [request]
(let [answers (db/answers-for (:id question))
(let [answers (db/answers-for quiz question)
results (->> (map :value answers) frequencies)]
(layout/render request "quiz/results.html"
{:title (:title quiz)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment