This commit is contained in:
Paul Zinselmeyer 2023-11-05 23:01:47 +01:00
parent f5485b773b
commit 4ce5c5270b
Signed by: pfzetto
GPG key ID: 4EEF46A5B276E648
11 changed files with 1206 additions and 131 deletions

View file

@ -15,8 +15,6 @@
url = "github:ipetkov/crane"; url = "github:ipetkov/crane";
inputs = { inputs = {
nixpkgs.follows = "nixpkgs"; nixpkgs.follows = "nixpkgs";
flake-utils.follows = "flake-utils";
rust-overlay.follows = "rust-overlay";
}; };
}; };
}; };
@ -42,6 +40,7 @@
(pkgs.lib.hasSuffix "\.md" path) || (pkgs.lib.hasSuffix "\.md" path) ||
(pkgs.lib.hasSuffix "\.stpl" path) || (pkgs.lib.hasSuffix "\.stpl" path) ||
(pkgs.lib.hasInfix "static" path) || (pkgs.lib.hasInfix "static" path) ||
(pkgs.lib.hasInfix "zettoit-style" path) ||
(craneLib.filterCargoSources path type) (craneLib.filterCargoSources path type)
; ;
}; };

View file

@ -96,6 +96,24 @@ impl Question for SingleChoiceQuestion {
acc acc
}, },
), ),
submissions_correct: &self.submissions.iter().fold(
vec![0; self.inner.answers.len()],
|mut acc, (_, v)| {
if *v == self.inner.correct {
acc[*v as usize] += 1;
}
acc
},
),
submissions_wrong: &self.submissions.iter().fold(
vec![0; self.inner.answers.len()],
|mut acc, (_, v)| {
if *v != self.inner.correct {
acc[*v as usize] += 1;
}
acc
},
),
correct_answer: &self.inner.answers[self.inner.correct as usize], correct_answer: &self.inner.answers[self.inner.correct as usize],
answers: &self.inner.answers, answers: &self.inner.answers,
} }
@ -126,6 +144,8 @@ struct ViewerTemplate<'a> {
name: &'a str, name: &'a str,
total_submissions: u32, total_submissions: u32,
submissions: &'a [u32], submissions: &'a [u32],
submissions_correct: &'a [u32],
submissions_wrong: &'a [u32],
correct_answer: &'a str, correct_answer: &'a str,
answers: &'a [String], answers: &'a [String],
} }

View file

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 512 512"
version="1.1"
id="svg4"
sodipodi:docname="check.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="2.0058594"
inkscape:cx="256.24927"
inkscape:cy="256.24927"
inkscape:window-width="1370"
inkscape:window-height="2110"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
<path
d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-111 111-47-47c-9.4-9.4-24.6-9.4-33.9 0s-9.4 24.6 0 33.9l64 64c9.4 9.4 24.6 9.4 33.9 0L369 209z"
id="path2"
style="fill:#008000" />
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

1106
static/patternomaly.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 512 512"
version="1.1"
id="svg4"
sodipodi:docname="xmark.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="2.0058594"
inkscape:cx="256.24927"
inkscape:cy="256.24927"
inkscape:window-width="1370"
inkscape:window-height="2110"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
<path
d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"
id="path2"
style="fill:#ff0000" />
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -31,10 +31,12 @@ answers = [ "A", "B", "C", "D"]
correct = 0 correct = 0
</pre> </pre>
<span id="error" style="color: red;"></span>
<form method="post" hx-post="" hx-target="#error" hx-swap="innerHTML" enctype="multipart/form-data"> <form method="post" hx-post="" hx-target="#error" hx-swap="innerHTML" enctype="multipart/form-data">
<input type="file" name="quizfile"/> <input type="file" name="quizfile"/>
<button type="submit">Create Quiz</button> <button type="submit">
Create Quiz
<small id="error" style="color: red;"></small>
</button>
</form> </form>
</main> </main>
<a class="watermark" href="https://git2.zettoit.eu/zettoit"><img src="/static/zettoit-style/zettoit.svg" alt="zettoIT Logo"></a> <a class="watermark" href="https://git2.zettoit.eu/zettoit"><img src="/static/zettoit-style/zettoit.svg" alt="zettoIT Logo"></a>

View file

@ -11,21 +11,15 @@
<main class="container" hx-sse="connect:/<%= id %>/events?player=<%=player_id%> swap:message"> <main class="container" hx-sse="connect:/<%= id %>/events?player=<%=player_id%> swap:message">
<% } %> <% } %>
<% if let PlayerState::NotStarted = state { %> <% if let PlayerState::NotStarted = state { %>
<article>
<center>The Quiz hasn't started yet. Please wait for the first question.</center> <center>The Quiz hasn't started yet. Please wait for the first question.</center>
</article>
<% } else if let PlayerState::Answering{ inner_body } = state { %> <% } else if let PlayerState::Answering{ inner_body } = state { %>
<%- inner_body %> <%- inner_body %>
<% } else if let PlayerState::Waiting(_) = state{ %> <% } else if let PlayerState::Waiting(_) = state{ %>
<article aria-busy="true"> <center>You answered the current question. Please wait for the results.</center>
You answered the current question. Please wait for the results.
</article>
<% } else if let PlayerState::Result{ inner_body } = state{ %> <% } else if let PlayerState::Result{ inner_body } = state{ %>
<%- inner_body %> <%- inner_body %>
<% } else if let PlayerState::Completed(correct) = state { %> <% } else if let PlayerState::Completed(correct) = state { %>
<article> <center>The Quiz finished. You can close this tab now. You answered <b><%= correct*100.0 %>%</b> correctly.</center>
The Quiz finished. You can close this tab now. You answered <b><%= correct*100.0 %>%</b> correctly.
</article>
<% } %> <% } %>
<% if !htmx { %> <% if !htmx { %>

View file

@ -1,10 +1,8 @@
<article> <h1><%= name %></h1>
<h1><%= name %></h1> <% for (index, answer) in answers.iter().enumerate() { %>
<% for (index, answer) in answers.iter().enumerate() { %>
<form method="POST" hx-post="" hx-target="closest main"> <form method="POST" hx-post="" hx-target="closest main">
<input type="hidden" name="player_id" value="<%= player_id %>"></input> <input type="hidden" name="player_id" value="<%= player_id %>"></input>
<input type="hidden" name="value" value="<%= index %>"></input> <input type="hidden" name="value" value="<%= index %>"></input>
<button type="submit"><%= answer %></button> <button type="submit"><%= answer %></button>
</form> </form>
<% } %> <% } %>
</article>

View file

@ -1,10 +1,7 @@
<% if is_correct { %> <% if is_correct { %>
<article class="centered">
<h1>Correct</h1> <h1>Correct</h1>
<p>Your answer is correct. The correct answer is <b><%= correct_answer %></b>.</p> <p>Your answer is correct. The correct answer is <b><%= correct_answer %></b>.</p>
</article>
<% } else { %> <% } else { %>
<article class="centered">
<h1>Wrong</h1> <h1>Wrong</h1>
<p> <p>
Your answer is incorrect. The correct answer is <b><%= correct_answer %></b>. Your answer is incorrect. The correct answer is <b><%= correct_answer %></b>.
@ -14,5 +11,4 @@
You didn't answer the question. You didn't answer the question.
<% } %> <% } %>
</p> </p>
</article>
<% } %> <% } %>

View file

@ -1,7 +1,6 @@
<h2><%= name %></h2> <h2><%= name %></h2>
<span>Total Participants: <b><%= total_submissions %></b></span> <span>Total Participants: <b><%= total_submissions %></b></span>
<% if show_result { %> <% if show_result { %>
<br/>
<span>The correct answer is: <b><%= correct_answer %></b></span> <span>The correct answer is: <b><%= correct_answer %></b></span>
<% } %> <% } %>
@ -18,34 +17,72 @@
"<%= answer %>", "<%= answer %>",
<% } %> <% } %>
], ],
<% if show_result { %>
datasets: [
{
label: "correct answers",
data: [
<% for submissions in submissions_correct.iter() { %>
<%= submissions %>,
<% } %>
],
borderWidth: 1,
borderColor: '#fff',
backgroundColor: '#fff',
},
{
label: "wrong answers",
data: [
<% for submissions in submissions_wrong.iter() { %>
<%= submissions %>,
<% } %>
],
borderWidth: 2,
borderColor: '#fff',
backgroundColor: [ pattern.draw('diagonal-right-left', '#000000') ],
}
]
<% } else { %>
datasets: [{ datasets: [{
label: "# der Stimmen",
data: [ data: [
<% for submissions in submissions.iter() { %> <% for submissions in submissions.iter() { %>
<%= submissions %>, <%= submissions %>,
<% } %> <% } %>
], ],
borderWidth: 1
borderWidth: 2,
borderColor: '#FFF',
backgroundColor: [ pattern.draw('diagonal-right-left', '#000000') ]
}] }]
<% } %>
}, },
options: { options: {
plugins: {
legend: { legend: {
display: false display: false
}
}, },
scales: { scales: {
x: { x: {
stacked: true,
ticks: { ticks: {
font: { font: {
size: 64 size: 64,
} family: 'monospace'
},
color: '#FFF'
} }
}, },
y: { y: {
beginAtZero: true, beginAtZero: true,
stacked: true,
ticks: { ticks: {
font: { font: {
size:24 size: 16,
} family: 'monospace'
},
color: '#FFF'
} }
} }
} }

View file

@ -11,11 +11,14 @@
filter: invert(); filter: invert();
width: 100%; width: 100%;
height: auto; height: auto;
max-height: 90vh;
max-width: 90wh;
} }
</style> </style>
</head> </head>
<body> <body>
<script src="/static/chart.js"></script> <script src="/static/chart.js"></script>
<script src="/static/patternomaly.js"></script>
<main class="container" hx-sse="connect:/<%= id %>/view/events swap:message"> <main class="container" hx-sse="connect:/<%= id %>/view/events swap:message">
<% } %> <% } %>
<% if let ViewerState::Answering{ inner_body } = state { %> <% if let ViewerState::Answering{ inner_body } = state { %>
@ -34,15 +37,11 @@
<% } %> <% } %>
<% } else if let ViewerState::NotStarted((player, qrcode, url)) = state { %> <% } else if let ViewerState::NotStarted((player, qrcode, url)) = state { %>
</article>
<center class="qrcode"><%- qrcode %></center> <center class="qrcode"><%- qrcode %></center>
<center>or visit <%= url %></center> <center>or visit <%= url %></center>
<button hx-post="" class="outline">Start Quiz with <b><%= player %></b> Players</button> <button hx-post="" class="outline">Start Quiz with <b><%= player %></b> Players</button>
</article>
<% } else {%> <% } else {%>
<article>
The Quiz finished. You can close this tab now. The Quiz finished. You can close this tab now.
</article>
<% } %> <% } %>
<% if !htmx { %> <% if !htmx { %>
</main> </main>