templates thml nove 4.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
  7. <title>Kvíz: Který učitel na GJS jsi ty?</title>
  8. <script src="https://cdn.tailwindcss.com"></script>
  9. <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
  10. <style>
  11. body { background-color: #f0f4f8; }
  12. .gjs-blue { background-color: #0055a4; }
  13. .card { border-radius: 15px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
  14. </style>
  15. <script>
  16. function quizApp() {
  17. return {
  18. zacalqiz: false,
  19. otazky: [],
  20. // answers: { [otazka.id]: index vybrané možnosti }
  21. // Slovník místo samostatných XxxBody proměnných – getSummary() pak
  22. // nepotřebuje hardcoded seznam učitelů a funguje pro libovolná data.
  23. answers: {},
  24. async startQuiz() {
  25. this.zacalqiz = !this.zacalqiz;
  26. if (this.zacalqiz && !this.otazky.length) {
  27. const res = await fetch('/api/questions?count=5');
  28. this.otazky = await res.json();
  29. }
  30. },
  31. getSummary() {
  32. const scores = {};
  33. for (const otazka of this.otazky) {
  34. const i = this.answers[otazka.id];
  35. if (i !== undefined)
  36. scores[otazka.results[i]] = (scores[otazka.results[i]] ?? 0) + 1;
  37. }
  38. const top = Object.entries(scores).sort((a, b) => b[1] - a[1])[0];
  39. return top
  40. ? { teacher: top[0], similarityPercent: Math.round(top[1] / Object.keys(this.answers).length * 100), scores }
  41. : { teacher: null, similarityPercent: 0, scores };
  42. }
  43. }
  44. }
  45. document.addEventListener('alpine:init', () => {
  46. window.getSummary = () => Alpine.$data(document.querySelector('[x-data]')).getSummary();
  47. });
  48. </script>
  49. </head>
  50. <body x-data="quizApp()">
  51. <template x-if="!zacalqiz">
  52. <div>
  53. <h1>silly_qiz</h1>
  54. <h3 class="rainbow">toto bude mega giga silly qiz, aby jste mohli zjistit který z učítelů gimjs jste :3</h3>
  55. <a href="{{ url_for('index') }}">Začít kvíz</a>
  56. </div>
  57. </template>
  58. <template x-if="zacalqiz">
  59. <div class="flex flex-col items-center justify-center min-h-screen p-4" x-data="{ CurrentOtazka: 0 }">
  60. <div class="card bg-white w-full max-w-lg p-6 border-t-8 border-blue-700">
  61. <h1 class="text-2xl font-bold text-center text-gray-800 mb-8">Který učitel na GJS jsi ty?</h1>
  62. <div class="mb-8">
  63. <p class="text-lg font-semibold text-gray-700 mb-4 text-center" x-text="otazky[CurrentOtazka].question"></p>
  64. <div class="space-y-3">
  65. <template x-for="(option, index) in otazky[CurrentOtazka].options" :key="index">
  66. <label class="block p-3 border rounded-lg cursor-pointer hover:bg-blue-50 transition">
  67. <input type="radio"
  68. :name="'q' + otazky[CurrentOtazka].id"
  69. :value="index"
  70. :checked="answers[otazky[CurrentOtazka].id] === index"
  71. @change="answers[otazky[CurrentOtazka].id] = index"
  72. class="mr-2">
  73. <span x-text="option"></span>
  74. </label>
  75. </template>
  76. </div>
  77. </div>
  78. <div class="flex justify-between mt-10">
  79. <button class="px-6 py-2 bg-gray-200 text-gray-700 rounded font-bold hover:bg-gray-300 transition"
  80. @click="CurrentOtazka = Math.max(CurrentOtazka - 1, 0)"
  81. :disabled="CurrentOtazka === 0">Předchozí</button>
  82. <button class="px-6 py-2 gjs-blue text-white rounded font-bold hover:opacity-90 transition"
  83. @click="CurrentOtazka = Math.min(CurrentOtazka + 1, otazky.length - 1)"
  84. :disabled="CurrentOtazka >= otazky.length - 1">Další</button>
  85. </div>
  86. </div>
  87. </div>
  88. </template>
  89. <button @click="startQuiz()">Začít kvíz</button>
  90. </body>
  91. </html>