Add a way of validating answers and render whole group of questions not just one file at a time. Add a cs-fixer package

This commit is contained in:
Krzysztof Płaczek
2024-10-24 16:23:43 +02:00
parent adb1449085
commit d07e20a1d5
13 changed files with 289 additions and 110 deletions

5
.gitignore vendored
View File

@@ -14,3 +14,8 @@
/public/assets/ /public/assets/
/assets/vendor/ /assets/vendor/
###< symfony/asset-mapper ### ###< symfony/asset-mapper ###
###> php-cs-fixer/shim ###
/.php-cs-fixer.php
/.php-cs-fixer.cache
###< php-cs-fixer/shim ###

13
.php-cs-fixer.dist.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
$finder = (new PhpCsFixer\Finder())
->in(__DIR__)
->exclude('var')
;
return (new PhpCsFixer\Config())
->setRules([
'@Symfony' => true,
])
->setFinder($finder)
;

View File

@@ -8,6 +8,7 @@
"ext-ctype": "*", "ext-ctype": "*",
"ext-iconv": "*", "ext-iconv": "*",
"efficience-it/certification-symfony": "^1.0", "efficience-it/certification-symfony": "^1.0",
"php-cs-fixer/shim": "^3.64",
"symfony/asset": "7.1.*", "symfony/asset": "7.1.*",
"symfony/asset-mapper": "7.1.*", "symfony/asset-mapper": "7.1.*",
"symfony/console": "7.1.*", "symfony/console": "7.1.*",

54
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "37fda8896febb7725269604fcf26625b", "content-hash": "4cecbae9a6775775e8fcd1192a4860ae",
"packages": [ "packages": [
{ {
"name": "composer/semver", "name": "composer/semver",
@@ -97,6 +97,58 @@
}, },
"type": "library" "type": "library"
}, },
{
"name": "php-cs-fixer/shim",
"version": "v3.64.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/shim.git",
"reference": "81ccfd24baf3a10810dab1152c403981a790b837"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/81ccfd24baf3a10810dab1152c403981a790b837",
"reference": "81ccfd24baf3a10810dab1152c403981a790b837",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-tokenizer": "*",
"php": "^7.4 || ^8.0"
},
"replace": {
"friendsofphp/php-cs-fixer": "self.version"
},
"suggest": {
"ext-dom": "For handling output formats in XML",
"ext-mbstring": "For handling non-UTF8 characters."
},
"bin": [
"php-cs-fixer",
"php-cs-fixer.phar"
],
"type": "application",
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Dariusz Rumiński",
"email": "dariusz.ruminski@gmail.com"
}
],
"description": "A tool to automatically fix PHP code style",
"support": {
"issues": "https://github.com/PHP-CS-Fixer/shim/issues",
"source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.64.0"
},
"time": "2024-08-30T23:10:11+00:00"
},
{ {
"name": "psr/cache", "name": "psr/cache",
"version": "3.0.0", "version": "3.0.0",

View File

@@ -4,29 +4,56 @@ namespace App\Controller;
use App\Service\QuestionsService; use App\Service\QuestionsService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Attribute\Route;
class ChallengeController extends AbstractController class ChallengeController extends AbstractController
{ {
#[Route('/challenge', name: 'app_challenges')]
#[Route('/challenge', name: 'app_challenge')]
public function randomChallenge(): Response public function randomChallenge(): Response
{ {
return $this->render('challenge/start.html.twig'); return $this->render('challenge/start.html.twig');
} }
#[Route('/list', name: 'app_list')] #[Route('/', name: 'app_home')]
public function list(QuestionsService $questionsService): Response public function list(QuestionsService $questionsService): Response
{ {
$listOfChallenges = $questionsService->getList(); $listOfChallenges = $questionsService->getList();
return $this->render('challenge/list.html.twig', ['list' => $listOfChallenges]); return $this->render('challenge/list.html.twig', ['list' => $listOfChallenges]);
} }
#[Route('/challenge/{challenge<.*>}', name: 'app_challenge')] #[Route('/challenge/{challenge<.*>}', name: 'app_challenge', methods: ['GET'])]
public function challenge(QuestionsService $questionsService, string $challenge): Response public function challenge(QuestionsService $questionsService, string $challenge): Response
{ {
$questions = $questionsService->getQuestions($challenge); $questions = $questionsService->getQuestions($challenge);
return $this->render('challenge/list.html.twig', ['list' => $questions, 'challenge' => $challenge]);
return $this->render('challenge/start.html.twig', ['questions' => $questions, 'challenge' => $challenge]);
}
#[Route('/challenge/{challenge<.*>}', name: 'app_challenge2', methods: ['POST'])]
public function challengeSubmit(Request $request, QuestionsService $questionsService, string $challenge): Response
{
$answers = $request->getPayload()->all('answer');
$questions = $questionsService->questionsById($request->getPayload()->all('question_id'));
//dd($answers);
//dd($questionsService->questionsById($request->getPayload()->all('question_id')));
//$x = $request->getPayload()->get('question_id');
//dd($questionsService->questionsById($request->getPayload()->all('question_id')));
//dd($request->getPayload()->all());
//$questions = $questionsService->getQuestions($challenge);
return $this->render('challenge/submit.html.twig', ['questions' => $questions, 'challenge' => $challenge, 'answers' => $answers]);
}
#[Route('/challenge_group/{group<.*>}', name: 'app_challenge_group')]
public function randomChallengeGroup(QuestionsService $questionsService, string $group): Response
{
$questions = $questionsService->getQuestionsGroup($group);
return $this->render('challenge/start_group.html.twig', ['questions' => $questions, 'group' => $group]);
} }
} }

View File

@@ -9,12 +9,11 @@ use Symfony\Component\Routing\Attribute\Route;
class HomeController extends AbstractController class HomeController extends AbstractController
{ {
#[Route('/', name: 'app_home')] #[Route('/home')]
public function home(QuestionsService $questionsService): Response public function home(QuestionsService $questionsService): Response
{ {
$questions = $questionsService->getQuestions(); $questions = $questionsService->getQuestions();
return $this->render('home/index.html.twig', ['questions' => $questions]); return $this->render('home/index.html.twig', ['questions' => $questions]);
} }
} }

View File

@@ -12,27 +12,66 @@ class QuestionsService
{ {
} }
public function getQuestions(?string $file): array public function getQuestions(?string $file = null, bool $shuffle = true): array
{ {
$questions = []; $questions = [];
foreach ($this->getQuestionFiles($file) as $file) { foreach ($this->getQuestionFiles(file: $file) as $file) {
$yamlFile = Yaml::parseFile($file->getRealPath()); $yamlFile = Yaml::parseFile($file->getRealPath());
$questions = array_merge($questions, $yamlFile['questions']); $questions = array_merge($questions, $yamlFile['questions']);
} }
if ($shuffle) {
shuffle($questions);
array_walk($questions, static function (array &$value): void {
shuffle($value['answers']);
$answers = 0;
foreach ($value['answers'] as $answer) {
$answers += $answer['correct'];
}
$value['type'] = $answers > 1 ? 'multiple' : 'single';
$value['count'] = $answers;
});
}
return $questions; return $questions;
} }
private function getQuestionFiles(?string $file = null): array public function questionsById(array $questionIds): array
{
$questions = [];
foreach ($this->getQuestionFiles() as $file) {
$yamlFile = Yaml::parseFile($file->getRealPath());
if (isset($yamlFile['questions'])) {
//dd(array_column($yamlFile['questions'], 'uuid'));
//dd($yamlFile['questions']);
$questions += array_combine(array_column($yamlFile['questions'], 'uuid'), $yamlFile['questions']);
//$questions = array_merge($questions, $yamlFile['questions']);
}
}
return array_filter($questions, fn(array $value): bool => in_array($value['uuid'], $questionIds, true));
}
private function getQuestionFiles(?string $file = null, ?string $group = null): array
{ {
$finder = new Finder(); $finder = new Finder();
if (null !== $file) {
if ($file) { if ($file) {
$finder->name($file); $finder->name($file);
} else { } else {
$finder->name('*.yaml'); $finder->name('*.yaml');
} }
$finder->in($this->paths);
}
if (null !== $group) {
$paths = array_filter(array_map(fn(string $path): string => $path . DIRECTORY_SEPARATOR . $group, $this->paths), 'is_dir');
$finder->in($paths);
$finder->name('*.yaml');
}
if (null === $group and null === $file) {
$finder->in($this->paths);
}
return iterator_to_array($finder->files()->in($this->paths)); return iterator_to_array($finder->files());
} }
/** /**
@@ -43,4 +82,18 @@ class QuestionsService
return $this->getQuestionFiles(); return $this->getQuestionFiles();
} }
public function getQuestionsGroup(string $group, bool $shuffle = true): array
{
$questions = [];
foreach ($this->getQuestionFiles(group: $group) as $file) {
$yamlFile = Yaml::parseFile($file->getRealPath());
$questions = array_merge($questions, $yamlFile['questions']);
}
if ($shuffle) {
shuffle($questions);
array_walk($questions, static fn(array &$value): true => shuffle($value['answers']));
}
return $questions;
}
} }

View File

@@ -1,4 +1,16 @@
{ {
"php-cs-fixer/shim": {
"version": "3.64",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "3.0",
"ref": "16422bf8eac6c3be42afe07d37e2abc89d2bdf6b"
},
"files": [
".php-cs-fixer.dist.php"
]
},
"symfony/asset-mapper": { "symfony/asset-mapper": {
"version": "7.1", "version": "7.1",
"recipe": { "recipe": {

View File

@@ -45,7 +45,7 @@
<div class="flex flex-shrink-0 items-center"> <div class="flex flex-shrink-0 items-center">
{# <img class="h-8 w-auto" src="https://tailwindui.com/plus/img/logos/mark.svg?color=indigo&shade=500" alt="Your Company"> #} {# <img class="h-8 w-auto" src="https://tailwindui.com/plus/img/logos/mark.svg?color=indigo&shade=500" alt="Your Company"> #}
<a href=""> <a href="{{ path('app_home') }}">
<img class="h-[40px]" src="{{ asset('images/logo.png') }}" alt="logo"> <img class="h-[40px]" src="{{ asset('images/logo.png') }}" alt="logo">
</a> </a>
@@ -53,10 +53,10 @@
<div class="hidden sm:ml-6 sm:block"> <div class="hidden sm:ml-6 sm:block">
<div class="flex space-x-4"> <div class="flex space-x-4">
<!-- Current: "bg-gray-900 text-white", Default: "text-gray-300 hover:bg-gray-700 hover:text-white" --> <!-- Current: "bg-gray-900 text-white", Default: "text-gray-300 hover:bg-gray-700 hover:text-white" -->
<a href="#" class="rounded-md bg-gray-900 px-3 py-2 text-sm font-medium text-white" aria-current="page">Dashboard</a> <a href="#" class="rounded-md bg-gray-900 px-3 py-2 text-sm font-medium text-white" aria-current="page">Home</a>
<a href="#" class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white">Team</a> {# <a href="#" class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white">Team</a>#}
<a href="#" class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white">Projects</a> {# <a href="#" class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white">Projects</a>#}
<a href="#" class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white">Calendar</a> {# <a href="#" class="rounded-md px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white">Calendar</a>#}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -3,16 +3,16 @@
{% block body %} {% block body %}
<div class="mx-auto mt-5 max-w-7xl px-2 sm:px-6 lg:px-8"> <div class="mx-auto mt-5 max-w-7xl px-2 sm:px-6 lg:px-8">
<div class="mt-5 max-w-7xl px-2 sm:px-6 lg:px-8"> <div class="mt-5 max-w-7xl px-2 sm:px-6 lg:px-8">
{% set test = '' %} {% set currentGroup = '' %}
{% for challenge in list %} {% for challenge in list %}
{% if test != challenge.getRelativePath %} {% if currentGroup != challenge.getRelativePath %}
<h2 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-3xl sm:tracking-tight"> <h2 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-3xl sm:tracking-tight">
<a href="">{{ challenge.getRelativePath|replace({'_': ' '})|capitalize }} / All</a> <a href="{{ path('app_challenge_group', {'group': challenge.getRelativePath}) }}">{{ challenge.getRelativePath|replace({'_': ' '})|capitalize }} / All</a>
</h2> </h2>
{% endif %} {% endif %}
<h2 class="leading-7 hover:text-cyan-600 text-gray-900 sm:truncate sm:tracking-tight ms-8"> <h2 class="leading-7 hover:text-cyan-600 text-gray-900 sm:truncate sm:tracking-tight ms-8 text-sm">
<a href="{{ path('app_challenge', {'challenge': challenge.getfilename}) }}">{{ challenge.getFilenameWithoutExtension|replace({'_': ' '})|capitalize }}</a></h2> <a href="{{ path('app_challenge', {'challenge': challenge.getfilename}) }}">{{ challenge.getFilenameWithoutExtension|replace({'_': ' '})|capitalize }}</a></h2>
{% set test = challenge.getRelativePath %} {% set currentGroup = challenge.getRelativePath %}
{% endfor %} {% endfor %}
<div class="lg:flex lg:items-center lg:justify-between"> <div class="lg:flex lg:items-center lg:justify-between">
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">

View File

@@ -1,99 +1,52 @@
{% extends 'base.html.twig' %} {% extends 'base.html.twig' %}
{% block body %} {% block body %}
<div class="mx-auto mt-5 max-w-7xl px-2 sm:px-6 lg:px-8"> <div class="mx-auto mt-5 max-w-7xl px-2 sm:px-6 lg:px-8 pb-10">
<div class="lg:flex lg:items-center lg:justify-between"> <h1 class="mx-4 mb-4 font-semibold text-2xl">{{ challenge|replace({'.yaml': '', '_': ' '})|capitalize }}</h1>
<div class="min-w-0 flex-1">
<h2 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-3xl sm:tracking-tight">Back End Developer</h2>
<div class="mt-1 flex flex-col sm:mt-0 sm:flex-row sm:flex-wrap sm:space-x-6">
<div class="mt-2 flex items-center text-sm text-gray-500">
<svg class="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd"
d="M6 3.75A2.75 2.75 0 0 1 8.75 1h2.5A2.75 2.75 0 0 1 14 3.75v.443c.572.055 1.14.122 1.706.2C17.053 4.582 18 5.75 18 7.07v3.469c0 1.126-.694 2.191-1.83 2.54-1.952.599-4.024.921-6.17.921s-4.219-.322-6.17-.921C2.694 12.73 2 11.665 2 10.539V7.07c0-1.321.947-2.489 2.294-2.676A41.047 41.047 0 0 1 6 4.193V3.75Zm6.5 0v.325a41.622 41.622 0 0 0-5 0V3.75c0-.69.56-1.25 1.25-1.25h2.5c.69 0 1.25.56 1.25 1.25ZM10 10a1 1 0 0 0-1 1v.01a1 1 0 0 0 1 1h.01a1 1 0 0 0 1-1V11a1 1 0 0 0-1-1H10Z"
clip-rule="evenodd"/>
<path d="M3 15.055v-.684c.126.053.255.1.39.142 2.092.642 4.313.987 6.61.987 2.297 0 4.518-.345 6.61-.987.135-.041.264-.089.39-.142v.684c0 1.347-.985 2.53-2.363 2.686a41.454 41.454 0 0 1-9.274 0C3.985 17.585 3 16.402 3 15.055Z"/>
</svg>
Full-time
</div>
<div class="mt-2 flex items-center text-sm text-gray-500">
<svg class="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd"
d="m9.69 18.933.003.001C9.89 19.02 10 19 10 19s.11.02.308-.066l.002-.001.006-.003.018-.008a5.741 5.741 0 0 0 .281-.14c.186-.096.446-.24.757-.433.62-.384 1.445-.966 2.274-1.765C15.302 14.988 17 12.493 17 9A7 7 0 1 0 3 9c0 3.492 1.698 5.988 3.355 7.584a13.731 13.731 0 0 0 2.273 1.765 11.842 11.842 0 0 0 .976.544l.062.029.018.008.006.003ZM10 11.25a2.25 2.25 0 1 0 0-4.5 2.25 2.25 0 0 0 0 4.5Z"
clip-rule="evenodd"/>
</svg>
Remote
</div>
<div class="mt-2 flex items-center text-sm text-gray-500">
<svg class="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path d="M10.75 10.818v2.614A3.13 3.13 0 0 0 11.888 13c.482-.315.612-.648.612-.875 0-.227-.13-.56-.612-.875a3.13 3.13 0 0 0-1.138-.432ZM8.33 8.62c.053.055.115.11.184.164.208.16.46.284.736.363V6.603a2.45 2.45 0 0 0-.35.13c-.14.065-.27.143-.386.233-.377.292-.514.627-.514.909 0 .184.058.39.202.592.037.051.08.102.128.152Z"/>
<path fill-rule="evenodd"
d="M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0Zm-8-6a.75.75 0 0 1 .75.75v.316a3.78 3.78 0 0 1 1.653.713c.426.33.744.74.925 1.2a.75.75 0 0 1-1.395.55 1.35 1.35 0 0 0-.447-.563 2.187 2.187 0 0 0-.736-.363V9.3c.698.093 1.383.32 1.959.696.787.514 1.29 1.27 1.29 2.13 0 .86-.504 1.616-1.29 2.13-.576.377-1.261.603-1.96.696v.299a.75.75 0 1 1-1.5 0v-.3c-.697-.092-1.382-.318-1.958-.695-.482-.315-.857-.717-1.078-1.188a.75.75 0 1 1 1.359-.636c.08.173.245.376.54.569.313.205.706.353 1.138.432v-2.748a3.782 3.782 0 0 1-1.653-.713C6.9 9.433 6.5 8.681 6.5 7.875c0-.805.4-1.558 1.097-2.096a3.78 3.78 0 0 1 1.653-.713V4.75A.75.75 0 0 1 10 4Z"
clip-rule="evenodd"/>
</svg>
$120k &ndash; $140k
</div>
<div class="mt-2 flex items-center text-sm text-gray-500">
<svg class="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd"
d="M5.75 2a.75.75 0 0 1 .75.75V4h7V2.75a.75.75 0 0 1 1.5 0V4h.25A2.75 2.75 0 0 1 18 6.75v8.5A2.75 2.75 0 0 1 15.25 18H4.75A2.75 2.75 0 0 1 2 15.25v-8.5A2.75 2.75 0 0 1 4.75 4H5V2.75A.75.75 0 0 1 5.75 2Zm-1 5.5c-.69 0-1.25.56-1.25 1.25v6.5c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25v-6.5c0-.69-.56-1.25-1.25-1.25H4.75Z"
clip-rule="evenodd"/>
</svg>
Closing on January 9, 2020
</div>
</div>
</div>
<div class="mt-5 flex lg:ml-4 lg:mt-0">
<span class="hidden sm:block">
<button type="button" class="inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50">
<svg class="-ml-0.5 mr-1.5 h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path d="m2.695 14.762-1.262 3.155a.5.5 0 0 0 .65.65l3.155-1.262a4 4 0 0 0 1.343-.886L17.5 5.501a2.121 2.121 0 0 0-3-3L3.58 13.419a4 4 0 0 0-.885 1.343Z"/>
</svg>
Edit
</button>
</span>
<span class="ml-3 hidden sm:block"> <form method="post">
<button type="button" class="inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"> <div>
<svg class="-ml-0.5 mr-1.5 h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon"> {% for question in questions %}
<path d="M12.232 4.232a2.5 2.5 0 0 1 3.536 3.536l-1.225 1.224a.75.75 0 0 0 1.061 1.06l1.224-1.224a4 4 0 0 0-5.656-5.656l-3 3a4 4 0 0 0 .225 5.865.75.75 0 0 0 .977-1.138 2.5 2.5 0 0 1-.142-3.667l3-3Z"/> <input name="question_id[]" type="hidden" value="{{ question.uuid }}"/>
<path d="M11.603 7.963a.75.75 0 0 0-.977 1.138 2.5 2.5 0 0 1 .142 3.667l-3 3a2.5 2.5 0 0 1-3.536-3.536l1.225-1.224a.75.75 0 0 0-1.061-1.06l-1.224 1.224a4 4 0 1 0 5.656 5.656l3-3a4 4 0 0 0-.225-5.865Z"/> <div class="mx-4 mb-8">
</svg> <h2 class="mb-3 text-sm">{{ loop.index }}. {{ question.question }}</h2>
View {% for answer in question.answers %}
</button> <div class="mb-2">
</span> <label class="ms-4 mb-2 text-gray-800 text-sm">
<input type="{% if question.type == 'single' %}radio{% else %}checkbox{% endif %}" class="rounded text-pink-500" value="{{ answer.value }}"
name="answer[{{ question.uuid }}][]">
{{ answer.value }}
</label>
</div>
{% endfor %}
</div>
{% endfor %}
<span class="sm:ml-3"> <span class="sm:ml-3">
<button type="button" <button type="submit"
class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"> class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
<svg class="-ml-0.5 mr-1.5 h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon"> <svg class="-ml-0.5 mr-1.5 h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z" <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z"
clip-rule="evenodd"/> clip-rule="evenodd"/>
</svg> </svg>
Publish Submit
</button> </button>
</span> </span>
<span class="sm:ml-3">
<!-- Dropdown --> <button type="reset"
<div class="relative ml-3 sm:hidden"> class="inline-flex items-center rounded-md bg-gray-200 px-3 py-2 text-sm font-semibold text-gray-400 shadow-sm hover:bg-gray-400 hover:text-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
<button type="button" <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="-ml-0.5 mr-1.5 h-5 w-5" >
class="inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:ring-gray-400" <path stroke-linecap="round" stroke-linejoin="round" d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/>
id="mobile-menu-button" aria-expanded="false" aria-haspopup="true">
More
<svg class="-mr-1 ml-1.5 h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z"
clip-rule="evenodd"/>
</svg> </svg>
Reset
</button> </button>
<div class="absolute right-0 z-10 -mr-1 mt-2 w-48 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" </span>
aria-orientation="vertical" aria-labelledby="mobile-menu-button" tabindex="-1">
<!-- Active: "bg-gray-100", Not Active: "" -->
<a href="#" class="block px-4 py-2 text-sm text-gray-700" role="menuitem" tabindex="-1" id="mobile-menu-item-0">Edit</a>
<a href="#" class="block px-4 py-2 text-sm text-gray-700" role="menuitem" tabindex="-1" id="mobile-menu-item-1">View</a>
</div>
</div>
</div>
</div> </div>
</form>
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -0,0 +1,30 @@
{% extends 'base.html.twig' %}
{% block body %}
<div class="mx-auto mt-5 max-w-7xl px-2 sm:px-6 lg:px-8 pb-10">
{% for question in questions %}
<div class="mx-4 mb-8">
<h2 class="mb-3 text-sm">{{ loop.index }}. {{ question.question }}</h2>
{% for answer in question.answers %}
<div class="mb-2">
<label class="ms-4 mb-2 text-gray-800 text-sm">
<input type="radio" class="rounded text-pink-500" name="{{ question.uuid }}">
{{ answer.value }}
</label>
</div>
{% endfor %}
</div>
{% endfor %}
<span class="sm:ml-3">
<button type="button"
class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
<svg class="-ml-0.5 mr-1.5 h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" data-slot="icon">
<path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z"
clip-rule="evenodd"/>
</svg>
Submit
</button>
</span>
</div>
{% endblock %}

View File

@@ -0,0 +1,34 @@
{% extends 'base.html.twig' %}
{% block body %}
<div class="mx-auto mt-5 max-w-7xl px-2 sm:px-6 lg:px-8 pb-10">
<h1 class="mx-4 mb-4 font-semibold text-2xl">{{ challenge|replace({'.yaml': '', '_': ' '})|capitalize }}</h1>
<div>
{% for question in questions %}
<div class="mx-4 mb-8">
<h2 class="mb-3 text-sm">{{ loop.index }}. {{ question.question }}</h2>
{% for questionanswer in question.answers %}
<div class="mb-2">
<div class="ms-4 mb-2 m-4 text-gray-800 text-sm">
{% if answers[question.uuid] is defined %}
{% if questionanswer.value in answers[question.uuid] and questionanswer.correct == true %}
<span class="text-green-700 bg-green-200 p-2">{{ questionanswer.value }}</span>
{% elseif questionanswer.value in answers[question.uuid] and questionanswer.correct == false %}
<span class="text-red-700 bg-red-200 p-2">{{ questionanswer.value }}</span>
{% else %}
<span class="p-2">{{ questionanswer.value }}</span>
{% endif %}
{% else %}
{{ questionanswer.value }}
{% endif %}
</div>
</div>
{% endfor %}
<div class="ms-4 mt-4 mb-2 ">
<span class="text-gray-400 p-2 text-sm bg-gray-200">help: </span><a href="{{ question.help }}" target="_blank" class="text-gray-400 p-2 text-sm">{{ question.help }}</a>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}