Compare commits
43 Commits
128-testbr
...
141-richti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ac5dd794b | ||
|
|
d17d41e07a | ||
|
|
7f845b8f36 | ||
|
|
37f4a7b868 | ||
|
|
d929e6b5dd | ||
|
|
6e63e0876a | ||
|
|
d907390652 | ||
|
|
31e9618e1c | ||
|
|
73345bf6b2 | ||
|
|
6c7e4770d6 | ||
|
|
0fe5c0cac3 | ||
|
|
c912b63d8d | ||
|
|
177c200467 | ||
|
|
2a06add37e | ||
|
|
fd3464711b | ||
|
|
93e166ece0 | ||
|
|
096349c989 | ||
|
|
1014ea37ec | ||
|
|
e65cd408eb | ||
|
|
d2274960cb | ||
|
|
016c253bc4 | ||
|
|
9f0d80bc41 | ||
|
|
f8dad9f0bd | ||
|
|
d55c4babc0 | ||
|
|
4875ed9676 | ||
|
|
7fcad195bd | ||
|
|
78fbdc9cc6 | ||
|
|
4e399a5423 | ||
|
|
c56d850dfa | ||
|
|
136fa7864a | ||
|
|
e916c010fe | ||
|
|
809a4495d5 | ||
|
|
5ca48f9287 | ||
|
|
16471141b2 | ||
|
|
f008d932ab | ||
|
|
431e1c07c8 | ||
|
|
c41d9cc9b5 | ||
|
|
fec37580ed | ||
|
|
b06ed09492 | ||
|
|
1771cd0d77 | ||
|
|
609a3a423a | ||
|
|
aea07295d8 | ||
|
|
7e321af48c |
@@ -6,13 +6,19 @@ from django.contrib.auth.forms import PasswordChangeForm
|
|||||||
from django.contrib.auth import update_session_auth_hash
|
from django.contrib.auth import update_session_auth_hash
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import logout
|
from django.contrib.auth import logout
|
||||||
|
from library.models import QivipQuiz, QivipQuestion
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
@login_required
|
@login_required
|
||||||
def home(request):
|
def home(request):
|
||||||
return render(request, 'accounts/home.html')
|
my_quizzes_number=QivipQuiz.objects.filter(user_id=request.user).count()
|
||||||
|
my_questions_number = QivipQuestion.objects.filter(quiz_id__user_id=request.user).count()
|
||||||
|
context = {
|
||||||
|
'my_quizzes_number': my_quizzes_number,
|
||||||
|
'my_questions_number': my_questions_number,
|
||||||
|
}
|
||||||
|
return render(request, 'accounts/home.html', context=context)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,9 @@ load_dotenv(env_path)
|
|||||||
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'django-insecure-&psk#na5l=p3q8_a+-$4w1f^lt3lx1c@d*p4x$ymm_rn7pwb87')
|
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'django-insecure-&psk#na5l=p3q8_a+-$4w1f^lt3lx1c@d*p4x$ymm_rn7pwb87')
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
#DEBUG = True
|
DEBUG = True
|
||||||
DEBUG = os.environ.get('DJANGO_DEBUG', '') != 'False'
|
#DEBUG = False
|
||||||
|
#DEBUG = os.environ.get('DJANGO_DEBUG', '') != 'False'
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['127.0.0.1', 'localhost', '*']
|
ALLOWED_HOSTS = ['127.0.0.1', 'localhost', '*']
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
'channels',
|
'channels',
|
||||||
'django_cleanup',
|
'django_cleanup',
|
||||||
|
'django.contrib.humanize',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
@@ -93,7 +95,7 @@ CHANNEL_LAYERS = {
|
|||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "channels_redis.core.RedisChannelLayer",
|
"BACKEND": "channels_redis.core.RedisChannelLayer",
|
||||||
"CONFIG": {
|
"CONFIG": {
|
||||||
"hosts": [("127.0.0.1", 6379)],
|
"hosts": [("127.0.0.1", 6380)],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -159,7 +161,7 @@ STATIC_ROOT = BASE_DIR / "staticfiles"
|
|||||||
STATICFILES_DIRS = [BASE_DIR / 'static']
|
STATICFILES_DIRS = [BASE_DIR / 'static']
|
||||||
|
|
||||||
# WhiteNoise configuration
|
# WhiteNoise configuration
|
||||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'
|
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
||||||
WHITENOISE_SKIP_COMPRESS_EXTENSIONS = ['css', 'js']
|
WHITENOISE_SKIP_COMPRESS_EXTENSIONS = ['css', 'js']
|
||||||
# Return 404 instead of 500 for missing files
|
# Return 404 instead of 500 for missing files
|
||||||
WHITENOISE_MISSING_FILE_ERRNO = None
|
WHITENOISE_MISSING_FILE_ERRNO = None
|
||||||
@@ -174,3 +176,13 @@ import os
|
|||||||
|
|
||||||
MEDIA_URL = '/media/' # URL, um auf Medien-Dateien zuzugreifen
|
MEDIA_URL = '/media/' # URL, um auf Medien-Dateien zuzugreifen
|
||||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # Speicherort für hochgeladene Dateien
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # Speicherort für hochgeladene Dateien
|
||||||
|
|
||||||
|
# Email Settings
|
||||||
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||||
|
EMAIL_HOST = 'postoffice.katharineum.de'
|
||||||
|
EMAIL_PORT = 587 # 25
|
||||||
|
EMAIL_USE_TLS = True
|
||||||
|
EMAIL_HOST_USER = 'qivip-mail@katharineum.de'
|
||||||
|
EMAIL_HOST_PASSWORD = '<password>'
|
||||||
|
EMAIL_USE_SSL = False
|
||||||
|
DEFAULT_FROM_EMAIL = 'qivip-mail@katharineum.de'
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from .models import QivipFaq
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
|
class QivipFaqAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('question','answer',)
|
||||||
|
|
||||||
|
# Registrierung der Modelle im Admin
|
||||||
|
admin.site.register(QivipFaq, QivipFaqAdmin)
|
||||||
22
django/homepage/migrations/0001_initial.py
Normal file
22
django/homepage/migrations/0001_initial.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-06-01 17:16
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='QivipFAQs',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('question', models.CharField(max_length=200)),
|
||||||
|
('answer', models.CharField(max_length=1000)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
17
django/homepage/migrations/0002_rename_qivipfaqs_qivipfaq.py
Normal file
17
django/homepage/migrations/0002_rename_qivipfaqs_qivipfaq.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-06-01 17:30
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('homepage', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameModel(
|
||||||
|
old_name='QivipFAQs',
|
||||||
|
new_name='QivipFaq',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-06-01 17:31
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('homepage', '0002_rename_qivipfaqs_qivipfaq'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='qivipfaq',
|
||||||
|
name='answer',
|
||||||
|
field=models.TextField(max_length=1000),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='qivipfaq',
|
||||||
|
name='question',
|
||||||
|
field=models.TextField(max_length=200),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
class QivipFaq(models.Model):
|
||||||
|
question = models.TextField(max_length=200)
|
||||||
|
answer = models.TextField(max_length=1000)
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
|
from .models import QivipFaq
|
||||||
|
|
||||||
def home(request):
|
def home(request):
|
||||||
return render(request, 'homepage/home.html')
|
faqs=QivipFaq.objects.all()
|
||||||
|
context={"faqs": faqs}
|
||||||
|
return render(request, 'homepage/home.html', context)
|
||||||
|
|
||||||
def impress(request):
|
def impress(request):
|
||||||
return render(request, 'homepage/impress.html')
|
return render(request, 'homepage/impress.html')
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import QivipQuiz, QivipQuestion, QivipQuizFavorite, QuestionImage, QuizCategory, QuizImage
|
from .models import QivipQuiz, QivipQuestion, QivipQuizFavorite, QuestionImage, QuizCategory, QuizImage, QuizRating
|
||||||
|
|
||||||
# Für das QivipQuiz Modell
|
# Für das QivipQuiz Modell
|
||||||
class QivipQuizAdmin(admin.ModelAdmin):
|
class QivipQuizAdmin(admin.ModelAdmin):
|
||||||
list_display = ('name', 'user_id', 'status', 'category', 'creation_date', 'update_date') # Welche Felder sollen in der Übersicht angezeigt werden
|
list_display = ('name','published_at', 'user_id', 'status', 'category', 'creation_date', 'update_date') # Welche Felder sollen in der Übersicht angezeigt werden
|
||||||
search_fields = ('name', 'user_id__username', 'category__name') # Suchfelder
|
search_fields = ('name', 'user_id__username', 'category__name') # Suchfelder
|
||||||
list_filter = ('status', 'category') # Filteroptionen
|
list_filter = ('status', 'category') # Filteroptionen
|
||||||
# Für das QivipQuestion Modell
|
# Für das QivipQuestion Modell
|
||||||
class QivipQuestionAdmin(admin.ModelAdmin):
|
class QivipQuestionAdmin(admin.ModelAdmin):
|
||||||
list_display = ('id', 'quiz_id', 'data', 'creation_date', 'update_date')
|
list_display = ('id', 'quiz_id', 'data', 'creation_date', 'update_date', 'credits')
|
||||||
search_fields = ('data',)
|
search_fields = ('data',)
|
||||||
list_filter = ('quiz_id',)
|
list_filter = ('quiz_id',)
|
||||||
|
|
||||||
@@ -30,10 +30,35 @@ class QuizImageAdmin(admin.ModelAdmin):
|
|||||||
class QuestionImageAdmin(admin.ModelAdmin):
|
class QuestionImageAdmin(admin.ModelAdmin):
|
||||||
list_display = ('image',)
|
list_display = ('image',)
|
||||||
|
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
from .models import QuizCategory
|
||||||
|
|
||||||
|
class QuizCategoryForm(forms.ModelForm):
|
||||||
|
color = forms.CharField(
|
||||||
|
widget=forms.TextInput(attrs={'type': 'color'})
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = QuizCategory
|
||||||
|
fields = '__all__'
|
||||||
|
from django.utils.html import format_html
|
||||||
|
@admin.register(QuizCategory)
|
||||||
|
class QuizCategoryAdmin(admin.ModelAdmin):
|
||||||
|
form = QuizCategoryForm
|
||||||
|
list_display = ('name', 'color_preview', 'color')
|
||||||
|
|
||||||
|
def color_preview(self, obj):
|
||||||
|
return format_html(
|
||||||
|
'<div style="width: 24px; height: 24px; background-color: {}; border: 2px solid #000;"></div>',
|
||||||
|
obj.color
|
||||||
|
)
|
||||||
|
color_preview.short_description = "Farbe"
|
||||||
|
|
||||||
# Registrierung der Modelle im Admin
|
# Registrierung der Modelle im Admin
|
||||||
admin.site.register(QivipQuiz, QivipQuizAdmin)
|
admin.site.register(QivipQuiz, QivipQuizAdmin)
|
||||||
admin.site.register(QivipQuestion, QivipQuestionAdmin)
|
admin.site.register(QivipQuestion, QivipQuestionAdmin)
|
||||||
admin.site.register(QuizCategory, QuizCategoryAdmin)
|
#admin.site.register(QuizCategory, QuizCategoryAdmin)
|
||||||
admin.site.register(QivipQuizFavorite, QivipQuizFavoriteAdmin)
|
admin.site.register(QivipQuizFavorite, QivipQuizFavoriteAdmin)
|
||||||
admin.site.register(QuizImage, QuizImageAdmin)
|
admin.site.register(QuizImage, QuizImageAdmin)
|
||||||
admin.site.register(QuestionImage, QuestionImageAdmin)
|
admin.site.register(QuestionImage, QuestionImageAdmin)
|
||||||
@@ -1,11 +1,19 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from .models import QivipQuiz, QivipQuestion
|
from .models import QivipQuiz, QivipQuestion, QuizCategory
|
||||||
|
|
||||||
class QuizForm(forms.ModelForm):
|
class QuizForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = QivipQuiz
|
model = QivipQuiz
|
||||||
fields = ['name', 'description', 'status', 'category','difficulty','credits']
|
fields = ['name', 'description', 'status', 'category','difficulty','credits']
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(QuizForm, self).__init__(*args, **kwargs)
|
||||||
|
for field in self.fields.values():
|
||||||
|
field.widget.attrs.update({
|
||||||
|
'class': 'dark:bg-[#2a2f3a]! dark:text-white'
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
class QuestionForm(forms.ModelForm):
|
class QuestionForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = QivipQuestion
|
model = QivipQuestion
|
||||||
@@ -19,13 +27,20 @@ class QuizFilterForm(forms.Form):
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
min_amout_questions = forms.IntegerField(required=False, min_value=1, label="Minimale Anzahl an Fragen", widget=forms.NumberInput(attrs={
|
min_amount_questions = forms.IntegerField(required=False, min_value=1, label="Minimale Anzahl an Fragen", widget=forms.NumberInput(attrs={
|
||||||
'class': 'border-2 border-gray-300 rounded-lg p-2 w-full'
|
'class': 'border-2 border-gray-300 rounded-lg p-2 w-full'
|
||||||
}))
|
}))
|
||||||
|
|
||||||
max_amout_questions = forms.IntegerField(required=False, min_value=1, label="Maximale Anzahl an Fragen", widget=forms.NumberInput(attrs={
|
max_amount_questions = forms.IntegerField(required=False, min_value=1, label="Maximale Anzahl an Fragen", widget=forms.NumberInput(attrs={
|
||||||
'class': 'border-2 border-gray-300 rounded-lg p-2 w-full'
|
'class': 'border-2 border-gray-300 rounded-lg p-2 w-full'
|
||||||
}))
|
}))
|
||||||
user = forms.CharField(required=False, label="von User", widget=forms.TextInput(attrs={
|
user = forms.CharField(required=False, label="von User", widget=forms.TextInput(attrs={
|
||||||
'class': 'border-2 border-gray-300 rounded-lg p-2 w-full'
|
'class': 'border-2 border-gray-300 rounded-lg p-2 w-full'
|
||||||
}))
|
}))
|
||||||
|
categories = forms.ModelChoiceField(
|
||||||
|
queryset=QuizCategory.objects.filter().distinct(),
|
||||||
|
required=False,
|
||||||
|
label="Kategorie",
|
||||||
|
widget=forms.Select(attrs={
|
||||||
|
'class': 'border-2 border-gray-300 rounded-lg p-2 w-full dark:bg-[#2a2f3a] dark:text-white'
|
||||||
|
}))
|
||||||
18
django/library/migrations/0054_qivipquestion_credits.py
Normal file
18
django/library/migrations/0054_qivipquestion_credits.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-06-13 16:10
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('library', '0053_questionimage_quizimage_alter_qivipquestion_image_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='qivipquestion',
|
||||||
|
name='credits',
|
||||||
|
field=models.TextField(blank=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
django/library/migrations/0055_qivipquiz_published_at.py
Normal file
18
django/library/migrations/0055_qivipquiz_published_at.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-06-26 16:46
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('library', '0054_qivipquestion_credits'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='qivipquiz',
|
||||||
|
name='published_at',
|
||||||
|
field=models.DateTimeField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-06-27 12:35
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('library', '0055_qivipquiz_published_at'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='quizrating',
|
||||||
|
unique_together=set(),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
django/library/migrations/0057_quizcategory_color.py
Normal file
18
django/library/migrations/0057_quizcategory_color.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.7 on 2025-07-02 11:31
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('library', '0056_alter_quizrating_unique_together'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='quizcategory',
|
||||||
|
name='color',
|
||||||
|
field=models.CharField(default='#000000', help_text='Farbe als Hex-Code, z.B. #ff0000', max_length=7),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -3,7 +3,7 @@ from django.contrib.auth.models import User
|
|||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
import uuid
|
import uuid
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
class QuizImage(models.Model):
|
class QuizImage(models.Model):
|
||||||
image = models.ImageField(max_length=256,verbose_name="Bild", upload_to='quiz_images/', blank=True, null=True) # Bild speichern in media/quiz_images/
|
image = models.ImageField(max_length=256,verbose_name="Bild", upload_to='quiz_images/', blank=True, null=True) # Bild speichern in media/quiz_images/
|
||||||
@@ -59,6 +59,10 @@ class QivipQuiz(models.Model):
|
|||||||
credits=models.TextField(blank=True, editable=True)
|
credits=models.TextField(blank=True, editable=True)
|
||||||
average_rating = models.FloatField(default=3.0)
|
average_rating = models.FloatField(default=3.0)
|
||||||
rating_count = models.IntegerField(default=0)
|
rating_count = models.IntegerField(default=0)
|
||||||
|
published_at = models.DateTimeField(null=True, blank=True) # manuell gesetzt, wenn veröffentlicht
|
||||||
|
|
||||||
|
def is_published(self):
|
||||||
|
return self.published_at is not None and self.published_at <= timezone.now()
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
||||||
return self.name
|
return self.name
|
||||||
@@ -98,6 +102,7 @@ class QivipQuestion(models.Model):
|
|||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
related_name="questions"
|
related_name="questions"
|
||||||
)
|
)
|
||||||
|
credits=models.TextField(blank=True, editable=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.data[:50]
|
return self.data[:50]
|
||||||
@@ -110,9 +115,22 @@ class QuizRating(models.Model):
|
|||||||
rating = models.IntegerField(choices=[(i, str(i)) for i in range(1, 6)])
|
rating = models.IntegerField(choices=[(i, str(i)) for i in range(1, 6)])
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
class Meta:
|
#class Meta:
|
||||||
unique_together = ('quiz', 'participant_id')
|
#unique_together = ('quiz', 'participant_id')
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
# Update quiz average rating (immer, auch bei Updates)
|
||||||
|
quiz = self.quiz
|
||||||
|
total_ratings = quiz.ratings.count()
|
||||||
|
avg_rating = quiz.ratings.aggregate(models.Avg('rating'))['rating__avg']
|
||||||
|
quiz.average_rating = round(avg_rating, 1) if avg_rating else 3.0
|
||||||
|
quiz.rating_count = total_ratings
|
||||||
|
quiz.save()
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
is_new = self.pk is None
|
is_new = self.pk is None
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
@@ -124,12 +142,18 @@ class QuizRating(models.Model):
|
|||||||
avg_rating = quiz.ratings.aggregate(models.Avg('rating'))['rating__avg']
|
avg_rating = quiz.ratings.aggregate(models.Avg('rating'))['rating__avg']
|
||||||
quiz.average_rating = round(avg_rating, 1) if avg_rating else 3.0
|
quiz.average_rating = round(avg_rating, 1) if avg_rating else 3.0
|
||||||
quiz.rating_count = total_ratings
|
quiz.rating_count = total_ratings
|
||||||
quiz.save()
|
quiz.save()"""
|
||||||
|
|
||||||
class QuizCategory(models.Model):
|
class QuizCategory(models.Model):
|
||||||
name = models.CharField(max_length=100, unique=True)
|
name = models.CharField(max_length=100, unique=True)
|
||||||
description = models.TextField(blank=True, null=True)
|
description = models.TextField(blank=True, null=True)
|
||||||
slug = models.SlugField(unique=True, blank=True)
|
slug = models.SlugField(unique=True, blank=True)
|
||||||
|
color= models.CharField(
|
||||||
|
max_length=7,
|
||||||
|
default="#000000",
|
||||||
|
help_text="Farbe als Hex-Code, z.B. #ff0000"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.slug:
|
if not self.slug:
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ app_name = 'library'
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.overview_quiz, name='overview_quiz'),
|
path('', views.overview_quiz, name='overview_quiz'),
|
||||||
|
path('my/', views.overview_quiz_my, name='overview_quiz_my'),
|
||||||
|
path('favorites/', views.overview_quiz_favorites, name='overview_quiz_favorites'),
|
||||||
|
|
||||||
path('new/', views.new_quiz, name='new_quiz'),
|
path('new/', views.new_quiz, name='new_quiz'),
|
||||||
path('edit/<int:pk>/', views.edit_quiz, name='edit_quiz'),
|
path('edit/<int:pk>/', views.edit_quiz, name='edit_quiz'),
|
||||||
path('delete/<int:pk>/', views.delete_quiz, name='delete_quiz'),
|
path('delete/<int:pk>/', views.delete_quiz, name='delete_quiz'),
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from .models import QivipQuiz
|
|||||||
from .forms import QuizFilterForm
|
from .forms import QuizFilterForm
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from urllib.parse import urlparse, urlunparse
|
||||||
# Übersicht aller Quizze
|
# Übersicht aller Quizze
|
||||||
|
|
||||||
|
|
||||||
@@ -23,13 +24,12 @@ def quiz_names_json(request):
|
|||||||
search = form.cleaned_data.get('search')
|
search = form.cleaned_data.get('search')
|
||||||
|
|
||||||
|
|
||||||
names = QivipQuiz.objects.all().annotate(max_amout_questions=Count('questions')).filter(max_amout_questions__gte=1, status='öffentlich', name__icontains=search)
|
names = QivipQuiz.objects.all().annotate(max_amount_questions=Count('questions')).filter(max_amount_questions__gte=1, status='öffentlich', name__icontains=search)
|
||||||
|
|
||||||
|
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
names = names | QivipQuiz.objects.filter(
|
names = names | QivipQuiz.objects.filter(
|
||||||
user_id=request.user.id,
|
user_id=request.user.id,
|
||||||
status='privat',
|
|
||||||
name__icontains=search
|
name__icontains=search
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -38,6 +38,167 @@ def quiz_names_json(request):
|
|||||||
|
|
||||||
return JsonResponse(names, safe=False)
|
return JsonResponse(names, safe=False)
|
||||||
|
|
||||||
|
|
||||||
|
def apply_quiz_filters(queryset, form):
|
||||||
|
|
||||||
|
if not form.is_valid():
|
||||||
|
return queryset
|
||||||
|
queryset = queryset.annotate(question_count=Count('questions'))
|
||||||
|
search = form.cleaned_data.get('search')
|
||||||
|
username = form.cleaned_data.get('user')
|
||||||
|
min_questions = form.cleaned_data.get('min_amount_questions')
|
||||||
|
max_questions = form.cleaned_data.get('max_amount_questions')
|
||||||
|
category = form.cleaned_data.get('categories')
|
||||||
|
|
||||||
|
filters = {}
|
||||||
|
|
||||||
|
if search:
|
||||||
|
filters['name__icontains'] = search
|
||||||
|
|
||||||
|
if min_questions is not None:
|
||||||
|
filters['question_count__gte'] = min_questions
|
||||||
|
|
||||||
|
if max_questions is not None:
|
||||||
|
filters['question_count__lte'] = max_questions
|
||||||
|
|
||||||
|
|
||||||
|
if category is not None:
|
||||||
|
filters['category'] = category
|
||||||
|
|
||||||
|
|
||||||
|
if username:
|
||||||
|
try:
|
||||||
|
user = User.objects.get(username=username)
|
||||||
|
filters['user_id'] = user.id
|
||||||
|
except User.DoesNotExist:
|
||||||
|
return queryset.none()
|
||||||
|
|
||||||
|
return queryset.filter(**filters)
|
||||||
|
|
||||||
|
|
||||||
|
def overview_quiz(request, connect="all"):
|
||||||
|
form = QuizFilterForm(request.GET)
|
||||||
|
|
||||||
|
user = request.user if request.user.is_authenticated else None
|
||||||
|
|
||||||
|
# Meine Quizzeze mit mind. 1 Frage
|
||||||
|
filter_my_quizzes = QivipQuiz.objects.none()
|
||||||
|
if user:
|
||||||
|
filter_my_quizzes = QivipQuiz.objects.annotate(max_amount_questions=Count('questions')).filter(
|
||||||
|
user_id=user.id,
|
||||||
|
max_amount_questions__gte=0
|
||||||
|
)
|
||||||
|
|
||||||
|
# Öffentliche Alle mit mind. 1 Frage
|
||||||
|
filter_all_quizzes = QivipQuiz.objects.annotate(max_amount_questions=Count('questions')).filter(
|
||||||
|
status='öffentlich',
|
||||||
|
max_amount_questions__gte=1
|
||||||
|
)
|
||||||
|
if user:
|
||||||
|
filter_all_quizzes = filter_all_quizzes.exclude(user_id=user.id)
|
||||||
|
|
||||||
|
# Favoriten mit mind. 1 Frage
|
||||||
|
favorite_quiz_ids = []
|
||||||
|
favorite_quizzes = QivipQuiz.objects.none()
|
||||||
|
if user:
|
||||||
|
favorite_quiz_ids = QivipQuizFavorite.objects.filter(user=user, favorite=True).values_list('quiz', flat=True)
|
||||||
|
favorite_quizzes = QivipQuiz.objects.annotate(max_amount_questions=Count('questions')).filter(
|
||||||
|
id__in=favorite_quiz_ids,
|
||||||
|
max_amount_questions__gte=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Suche anwenden, falls vorhanden
|
||||||
|
|
||||||
|
|
||||||
|
filter_my_quizzes = apply_quiz_filters(filter_my_quizzes, form)
|
||||||
|
filter_all_quizzes = apply_quiz_filters(filter_all_quizzes, form)
|
||||||
|
favorite_quizzes = apply_quiz_filters(favorite_quizzes, form)
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
filter_all_quizzes = apply_quiz_filters(filter_all_quizzes, form) | apply_quiz_filters(filter_my_quizzes, form)
|
||||||
|
|
||||||
|
# Treffer zählen
|
||||||
|
total_my = filter_my_quizzes.count()
|
||||||
|
total_all = filter_all_quizzes.count()
|
||||||
|
total_favorite = favorite_quizzes.count()
|
||||||
|
|
||||||
|
total_all_found=total_my + total_all + total_favorite
|
||||||
|
|
||||||
|
# Paginierung
|
||||||
|
paginator_my = Paginator(filter_my_quizzes.order_by('-creation_date'), 8)
|
||||||
|
paginator_all = Paginator(filter_all_quizzes.order_by('-published_at'), 8)
|
||||||
|
paginator_fav = Paginator(favorite_quizzes.order_by('-published_at'), 8)
|
||||||
|
|
||||||
|
my_page = request.GET.get('my_page', 1)
|
||||||
|
all_page = request.GET.get('all_page', 1)
|
||||||
|
fav_page = request.GET.get('favorite_page', 1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
my_quizzes = paginator_my.page(my_page)
|
||||||
|
except:
|
||||||
|
my_quizzes = paginator_my.page(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
all_quizzes = paginator_all.page(all_page)
|
||||||
|
except:
|
||||||
|
all_quizzes = paginator_all.page(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
favorite_quizzes = paginator_fav.page(fav_page)
|
||||||
|
except:
|
||||||
|
favorite_quizzes = paginator_fav.page(1)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'form': form,
|
||||||
|
'my_quizzes': my_quizzes,
|
||||||
|
'all_quizzes': all_quizzes,
|
||||||
|
'favorite_quizzes': favorite_quizzes,
|
||||||
|
'total_my': total_my,
|
||||||
|
'total_all': total_all,
|
||||||
|
'total_favorite': total_favorite,
|
||||||
|
'total_all_found':total_all_found,
|
||||||
|
'show_search': True,
|
||||||
|
'favorite_quiz_ids': list(favorite_quiz_ids),
|
||||||
|
'url_my': '/library/my/',
|
||||||
|
'url_all': '/library/',
|
||||||
|
'url_favorite': '/library/favorites/',
|
||||||
|
}
|
||||||
|
|
||||||
|
query_params = request.GET.copy()
|
||||||
|
|
||||||
|
querydict_my = query_params.copy()
|
||||||
|
querydict_all = query_params.copy()
|
||||||
|
querydict_fav = query_params.copy()
|
||||||
|
|
||||||
|
# Entferne die jeweiligen Seiten-Parameter, damit wir sie neu setzen können
|
||||||
|
querydict_my.pop('my_page', None)
|
||||||
|
querydict_all.pop('all_page', None)
|
||||||
|
querydict_fav.pop('favorite_page', None)
|
||||||
|
|
||||||
|
# Füge die "bereinigten" Querystrings dem context hinzu
|
||||||
|
context.update({
|
||||||
|
'querystring_my': querydict_my.urlencode(),
|
||||||
|
'querystring_all': querydict_all.urlencode(),
|
||||||
|
'querystring_favorite': querydict_fav.urlencode(),
|
||||||
|
})
|
||||||
|
|
||||||
|
if connect=="all":
|
||||||
|
context.update({"link":"library:overview_quiz"})
|
||||||
|
return render(request, 'library/overview_quiz.html', context)
|
||||||
|
elif connect=="my":
|
||||||
|
context.update({"link":"library:overview_quiz_my"})
|
||||||
|
return render(request, 'library/overview_quiz_my.html', context)
|
||||||
|
elif connect=="favorite":
|
||||||
|
context.update({"link":"library:overview_quiz_favorites"})
|
||||||
|
return render(request, 'library/overview_quiz_favorite.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
def overview_quiz_my(request):
|
||||||
|
return overview_quiz(request, connect="my")
|
||||||
|
|
||||||
|
|
||||||
|
def overview_quiz_favorites(request):
|
||||||
|
return overview_quiz(request, connect="favorite")
|
||||||
|
"""
|
||||||
def overview_quiz(request):
|
def overview_quiz(request):
|
||||||
# Filter
|
# Filter
|
||||||
form = QuizFilterForm(request.GET)
|
form = QuizFilterForm(request.GET)
|
||||||
@@ -53,28 +214,24 @@ def overview_quiz(request):
|
|||||||
|
|
||||||
# Initialize querysets
|
# Initialize querysets
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
filter_my_quizzes = QivipQuiz.objects.filter(user_id=request.user).annotate(max_amout_questions=Count('questions'))
|
filter_my_quizzes = QivipQuiz.objects.filter(user_id=request.user).annotate(max_amount_questions=Count('questions'))
|
||||||
favorite_quizzes = favorite_quizzes.filter(id__in=favorite_quiz_ids).annotate(max_amout_questions=Count('questions'))
|
favorite_quizzes = favorite_quizzes.filter(id__in=favorite_quiz_ids).annotate(max_amount_questions=Count('questions'))
|
||||||
filter_other_quizzes = QivipQuiz.objects.exclude(user_id=request.user)
|
filter_all_quizzes = QivipQuiz.objects.exclude(user_id=request.user)
|
||||||
else:
|
else:
|
||||||
favorite_quizzes = QivipQuiz.objects.none()
|
favorite_quizzes = QivipQuiz.objects.none()
|
||||||
filter_my_quizzes = QivipQuiz.objects.none()
|
filter_my_quizzes = QivipQuiz.objects.none()
|
||||||
filter_other_quizzes = QivipQuiz.objects.all()
|
filter_all_quizzes = QivipQuiz.objects.all()
|
||||||
|
|
||||||
# Apply common filters to other quizzes
|
|
||||||
filter_other_quizzes = filter_other_quizzes.annotate(max_amout_questions=Count('questions'))
|
|
||||||
filter_other_quizzes = filter_other_quizzes.filter(max_amout_questions__gte=1, status='öffentlich')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Apply common filters to all quizzes
|
||||||
|
filter_all_quizzes = filter_all_quizzes.annotate(max_amount_questions=Count('questions'))
|
||||||
|
filter_all_quizzes = filter_all_quizzes.filter(max_amount_questions__gte=1, status='öffentlich')
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
|
||||||
search = form.cleaned_data.get('search')
|
search = form.cleaned_data.get('search')
|
||||||
username= form.cleaned_data.get('user')
|
username= form.cleaned_data.get('user')
|
||||||
max_amout_questions= form.cleaned_data.get('max_amout_questions')
|
max_amount_questions= form.cleaned_data.get('max_amount_questions')
|
||||||
min_amout_questions= form.cleaned_data.get('min_amout_questions')
|
min_amount_questions= form.cleaned_data.get('min_amount_questions')
|
||||||
|
|
||||||
filters = {}
|
filters = {}
|
||||||
if username:
|
if username:
|
||||||
@@ -84,19 +241,19 @@ def overview_quiz(request):
|
|||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
favorite_quizzes = QivipQuiz.objects.none()
|
favorite_quizzes = QivipQuiz.objects.none()
|
||||||
filter_my_quizzes = QivipQuiz.objects.none()
|
filter_my_quizzes = QivipQuiz.objects.none()
|
||||||
filter_other_quizzes=QivipQuiz.objects.none()
|
filter_all_quizzes=QivipQuiz.objects.none()
|
||||||
|
|
||||||
if search:
|
if search:
|
||||||
filters['name__icontains'] = search
|
filters['name__icontains'] = search
|
||||||
if min_amout_questions:
|
if min_amount_questions:
|
||||||
filters['max_amout_questions__gte'] = min_amout_questions
|
filters['max_amount_questions__gte'] = min_amount_questions
|
||||||
if max_amout_questions:
|
if max_amount_questions:
|
||||||
filters['max_amout_questions__lte'] = max_amout_questions
|
filters['max_amount_questions__lte'] = max_amount_questions
|
||||||
|
|
||||||
try:
|
try:
|
||||||
filter_other_quizzes = filter_other_quizzes.filter(**filters)
|
filter_all_quizzes = filter_all_quizzes.filter(**filters)
|
||||||
except:
|
except:
|
||||||
filter_other_quizzes=QivipQuiz.objects.none()
|
filter_all_quizzes=QivipQuiz.objects.none()
|
||||||
try:
|
try:
|
||||||
filter_my_quizzes = filter_my_quizzes.filter(**filters)
|
filter_my_quizzes = filter_my_quizzes.filter(**filters)
|
||||||
except:
|
except:
|
||||||
@@ -116,12 +273,12 @@ def overview_quiz(request):
|
|||||||
except:
|
except:
|
||||||
my_quizzes = my_quizzes_paginator.page(1)
|
my_quizzes = my_quizzes_paginator.page(1)
|
||||||
|
|
||||||
# Pagination for other quizzes
|
# Pagination for all quizzes
|
||||||
other_quizzes_paginator = Paginator(filter_other_quizzes.order_by('-creation_date'), 8) # 8 quizzes per page
|
all_quizzes_paginator = Paginator(filter_all_quizzes.order_by('-creation_date'), 8) # 8 quizzes per page
|
||||||
try:
|
try:
|
||||||
other_quizzes = other_quizzes_paginator.page(request.GET.get('other_page', 1))
|
all_quizzes = all_quizzes_paginator.page(request.GET.get('all_page', 1))
|
||||||
except:
|
except:
|
||||||
other_quizzes = other_quizzes_paginator.page(1)
|
all_quizzes = all_quizzes_paginator.page(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -135,9 +292,9 @@ def overview_quiz(request):
|
|||||||
|
|
||||||
|
|
||||||
# Pagination for favorite_quizzes
|
# Pagination for favorite_quizzes
|
||||||
favorite_quizzes_paginator = Paginator(favorite_quizzes, 8) # 8 quizzes per page
|
favorite_quizzes_paginator = Paginator(favorite_quizzes, 8) # 9 quizzes per page
|
||||||
try:
|
try:
|
||||||
favorite_quizzes = favorite_quizzes_paginator.page(request.GET.get('my_page', 1))
|
favorite_quizzes = favorite_quizzes_paginator.page(request.GET.get('favorite_page', 1))
|
||||||
except:
|
except:
|
||||||
favorite_quizzes = favorite_quizzes_paginator.page(1)
|
favorite_quizzes = favorite_quizzes_paginator.page(1)
|
||||||
|
|
||||||
@@ -146,13 +303,13 @@ def overview_quiz(request):
|
|||||||
'favorite_quiz_ids': favorite_quiz_ids,
|
'favorite_quiz_ids': favorite_quiz_ids,
|
||||||
'favorite_quizzes':favorite_quizzes,
|
'favorite_quizzes':favorite_quizzes,
|
||||||
'my_quizzes': my_quizzes,
|
'my_quizzes': my_quizzes,
|
||||||
'other_quizzes': other_quizzes,
|
'all_quizzes': all_quizzes,
|
||||||
'form': form,
|
'form': form,
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(request, 'library/overview_quiz.html', context)
|
return render(request, 'library/overview_quiz.html', context)
|
||||||
|
"""
|
||||||
|
|
||||||
# Neues Quiz erstellen
|
|
||||||
@login_required
|
@login_required
|
||||||
def favorite_quiz(request, pk):
|
def favorite_quiz(request, pk):
|
||||||
quiz= get_object_or_404(QivipQuiz, pk=pk)
|
quiz= get_object_or_404(QivipQuiz, pk=pk)
|
||||||
@@ -163,6 +320,7 @@ def favorite_quiz(request, pk):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if favorite.favorite==True:
|
if favorite.favorite==True:
|
||||||
favorite.favorite_date = timezone.now()
|
favorite.favorite_date = timezone.now()
|
||||||
favorite.save()
|
favorite.save()
|
||||||
@@ -177,6 +335,7 @@ def favorite_quiz(request, pk):
|
|||||||
favorite=QivipQuizFavorite.objects.create(user=request.user, quiz=quiz, favorite=True, favorite_date=timezone.now())
|
favorite=QivipQuizFavorite.objects.create(user=request.user, quiz=quiz, favorite=True, favorite_date=timezone.now())
|
||||||
statement="Das Quiz '"+ favorite.quiz.name+ "' wurde erfolgreich zu den Favoriten hinzugefügt!"
|
statement="Das Quiz '"+ favorite.quiz.name+ "' wurde erfolgreich zu den Favoriten hinzugefügt!"
|
||||||
messages.success(request,statement )
|
messages.success(request,statement )
|
||||||
|
|
||||||
return redirect(request.META.get('HTTP_REFERER', 'library:overview_quiz'))
|
return redirect(request.META.get('HTTP_REFERER', 'library:overview_quiz'))
|
||||||
|
|
||||||
|
|
||||||
@@ -189,10 +348,19 @@ def new_quiz(request):
|
|||||||
|
|
||||||
|
|
||||||
form = QuizForm(request.POST, request.FILES)
|
form = QuizForm(request.POST, request.FILES)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
quiz = form.save(commit=False)
|
quiz = form.save(commit=False)
|
||||||
|
status = form.cleaned_data.get('status')
|
||||||
|
|
||||||
|
if status == 'öffentlich' and not quiz.published_at:
|
||||||
|
quiz.published_at = timezone.now()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
quiz_image=request.FILES['quiz_image']
|
quiz_image=request.FILES['quiz_image']
|
||||||
|
|
||||||
imagequiz=QuizImage.objects.create(image=quiz_image)
|
imagequiz=QuizImage.objects.create(image=quiz_image)
|
||||||
quiz.image=imagequiz
|
quiz.image=imagequiz
|
||||||
|
|
||||||
@@ -201,6 +369,8 @@ def new_quiz(request):
|
|||||||
|
|
||||||
|
|
||||||
quiz.user_id = request.user
|
quiz.user_id = request.user
|
||||||
|
|
||||||
|
|
||||||
#quiz.creator = request.user
|
#quiz.creator = request.user
|
||||||
quiz.save()
|
quiz.save()
|
||||||
#form.save_m2m() # Speichert die Many-to-Many Beziehungen (Tags)
|
#form.save_m2m() # Speichert die Many-to-Many Beziehungen (Tags)
|
||||||
@@ -216,8 +386,13 @@ def edit_quiz(request, pk):
|
|||||||
quiz = get_object_or_404(QivipQuiz, pk=pk, user_id=request.user)
|
quiz = get_object_or_404(QivipQuiz, pk=pk, user_id=request.user)
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = QuizForm(request.POST, instance=quiz, files=request.FILES)
|
form = QuizForm(request.POST, instance=quiz, files=request.FILES)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if 'reset_image' in request.POST:
|
if 'reset_image' in request.POST:
|
||||||
quiz.image = None
|
quiz.image = None
|
||||||
|
|
||||||
@@ -230,7 +405,12 @@ def edit_quiz(request, pk):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
quiz = form.save(commit=False)
|
||||||
|
|
||||||
|
# Beispiel: Status aus dem Formular holen
|
||||||
|
status = form.cleaned_data.get('status')
|
||||||
|
if status == 'öffentlich' and not quiz.published_at:
|
||||||
|
quiz.published_at = timezone.now()
|
||||||
|
|
||||||
form.save()
|
form.save()
|
||||||
for img in QuizImage.objects.all():
|
for img in QuizImage.objects.all():
|
||||||
@@ -308,6 +488,11 @@ def copy_quiz(request, pk):
|
|||||||
new_quiz.base_quiz_id = pk
|
new_quiz.base_quiz_id = pk
|
||||||
new_quiz.rating_count = 0
|
new_quiz.rating_count = 0
|
||||||
new_quiz.average_rating = 3.0
|
new_quiz.average_rating = 3.0
|
||||||
|
if original_quiz.status=="öffentlich":
|
||||||
|
new_quiz.published_at = timezone.now()
|
||||||
|
else:
|
||||||
|
new_quiz.published_at = None
|
||||||
|
|
||||||
new_quiz.save() # Speichern als neues Objekt
|
new_quiz.save() # Speichern als neues Objekt
|
||||||
# Optional: Beschreibung anpassen
|
# Optional: Beschreibung anpassen
|
||||||
# Alle zugehörigen Fragen kopieren
|
# Alle zugehörigen Fragen kopieren
|
||||||
@@ -417,6 +602,10 @@ def new_question(request):
|
|||||||
|
|
||||||
|
|
||||||
question.time_per_question = request.POST.get('time_per_question', '30')
|
question.time_per_question = request.POST.get('time_per_question', '30')
|
||||||
|
try:
|
||||||
|
question.credits=request.POST.get('credits',"")
|
||||||
|
except:
|
||||||
|
question.credits=""
|
||||||
question.save()
|
question.save()
|
||||||
#return modified(request, pk=quiz.pk)
|
#return modified(request, pk=quiz.pk)
|
||||||
return redirect('library:detail_quiz', pk=quiz.pk)
|
return redirect('library:detail_quiz', pk=quiz.pk)
|
||||||
@@ -582,7 +771,10 @@ def edit_question(request, pk):
|
|||||||
|
|
||||||
question.data = json.dumps(json_data)
|
question.data = json.dumps(json_data)
|
||||||
question.time_per_question = request.POST.get('time_per_question', '30')
|
question.time_per_question = request.POST.get('time_per_question', '30')
|
||||||
|
try:
|
||||||
|
question.credits=request.POST.get('credits',"")
|
||||||
|
except:
|
||||||
|
question.credits=""
|
||||||
|
|
||||||
question.save()
|
question.save()
|
||||||
for img in QuestionImage.objects.all():
|
for img in QuestionImage.objects.all():
|
||||||
@@ -597,6 +789,7 @@ def edit_question(request, pk):
|
|||||||
else:
|
else:
|
||||||
template_name = f'library/question/question_{question_type}.html'
|
template_name = f'library/question/question_{question_type}.html'
|
||||||
context = {
|
context = {
|
||||||
|
'credits':question.credits,
|
||||||
'question': {'data': question_data}, # Wrap in data structure expected by template
|
'question': {'data': question_data}, # Wrap in data structure expected by template
|
||||||
'quiz_id': question.quiz_id.pk,
|
'quiz_id': question.quiz_id.pk,
|
||||||
'quiz': question.quiz_id,
|
'quiz': question.quiz_id,
|
||||||
|
|||||||
@@ -264,6 +264,7 @@ class GameConsumer(AsyncWebsocketConsumer):
|
|||||||
|
|
||||||
@database_sync_to_async
|
@database_sync_to_async
|
||||||
def save_rating(self, participant_id, rating):
|
def save_rating(self, participant_id, rating):
|
||||||
|
from django.db import models
|
||||||
if not settings.QIVIP_CONFIG['ENABLE_RATING_SYSTEM']:
|
if not settings.QIVIP_CONFIG['ENABLE_RATING_SYSTEM']:
|
||||||
return False
|
return False
|
||||||
from library.models import QuizRating
|
from library.models import QuizRating
|
||||||
@@ -275,16 +276,23 @@ class GameConsumer(AsyncWebsocketConsumer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Update or create rating
|
# Update or create rating
|
||||||
|
"""
|
||||||
rating_obj, created = QuizRating.objects.get_or_create(
|
rating_obj, created = QuizRating.objects.get_or_create(
|
||||||
quiz=game.quiz_id,
|
quiz=game.quiz_id,
|
||||||
participant_id=participant_id,
|
participant_id=participant_id,
|
||||||
defaults={'rating': rating}
|
defaults={'rating': rating}
|
||||||
)
|
)
|
||||||
|
"""
|
||||||
|
rating_obj=QuizRating.objects.create(
|
||||||
|
quiz=game.quiz_id,
|
||||||
|
participant_id=participant_id,
|
||||||
|
rating=rating)
|
||||||
|
|
||||||
if not created:
|
|
||||||
rating_obj.rating = rating
|
rating_obj.rating = rating
|
||||||
rating_obj.save()
|
rating_obj.save()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except (QuizGame.DoesNotExist, QuizGameParticipant.DoesNotExist):
|
except (QuizGame.DoesNotExist, QuizGameParticipant.DoesNotExist):
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ game_connections = {}
|
|||||||
|
|
||||||
class LobbyConsumer(AsyncWebsocketConsumer):
|
class LobbyConsumer(AsyncWebsocketConsumer):
|
||||||
|
|
||||||
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
|
r = redis.Redis(host='localhost', port=6380, db=0, decode_responses=True)
|
||||||
|
|
||||||
async def connect(self):
|
async def connect(self):
|
||||||
self.join_code = self.scope['url_route']['kwargs']['join_code']
|
self.join_code = self.scope['url_route']['kwargs']['join_code']
|
||||||
@@ -147,7 +147,7 @@ class LobbyConsumer(AsyncWebsocketConsumer):
|
|||||||
|
|
||||||
# Zustand laden
|
# Zustand laden
|
||||||
try:
|
try:
|
||||||
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
|
r = redis.Redis(host='localhost', port=6380, db=0, decode_responses=True)
|
||||||
|
|
||||||
# Alte Teilnehmer aus Redis holen
|
# Alte Teilnehmer aus Redis holen
|
||||||
data = r.get(f"last_participants_{self.room_group_name}")
|
data = r.get(f"last_participants_{self.room_group_name}")
|
||||||
|
|||||||
@@ -147,26 +147,7 @@ def join_game(request):
|
|||||||
messages.error(request, "Dieses Spiel existiert nicht.")
|
messages.error(request, "Dieses Spiel existiert nicht.")
|
||||||
return render(request, 'play/join_game.html')
|
return render(request, 'play/join_game.html')
|
||||||
|
|
||||||
def finished(request, join_code):
|
|
||||||
try:
|
|
||||||
game = QuizGame.objects.get(join_code=join_code)
|
|
||||||
participant = None
|
|
||||||
participant_id = request.session.get('participant_id')
|
|
||||||
if participant_id:
|
|
||||||
participant = QuizGameParticipant.objects.filter(
|
|
||||||
quiz_game=game,
|
|
||||||
participant_id=participant_id
|
|
||||||
).first()
|
|
||||||
|
|
||||||
context = {
|
|
||||||
'join_code': join_code,
|
|
||||||
'is_host': str(game.host_id) == str(request.session.get('host_id')),
|
|
||||||
'participant_id': participant_id if participant else None,
|
|
||||||
'rating_enabled': settings.QIVIP_CONFIG['ENABLE_RATING_SYSTEM']
|
|
||||||
}
|
|
||||||
return render(request, 'play/game/finished.html', context)
|
|
||||||
except QuizGame.DoesNotExist:
|
|
||||||
return redirect('home')
|
|
||||||
|
|
||||||
def scores(request, join_code):
|
def scores(request, join_code):
|
||||||
quiz_game = get_object_or_404(QuizGame, join_code=join_code)
|
quiz_game = get_object_or_404(QuizGame, join_code=join_code)
|
||||||
@@ -207,8 +188,9 @@ def scores(request, join_code):
|
|||||||
'question_index': quiz_game.current_question_index,
|
'question_index': quiz_game.current_question_index,
|
||||||
'total_questions': len(questions)
|
'total_questions': len(questions)
|
||||||
})
|
})
|
||||||
|
"""
|
||||||
def finished(request, join_code):
|
def finished(request, join_code):
|
||||||
|
|
||||||
quiz_game = get_object_or_404(QuizGame, join_code=join_code)
|
quiz_game = get_object_or_404(QuizGame, join_code=join_code)
|
||||||
|
|
||||||
# Verify game state
|
# Verify game state
|
||||||
@@ -240,6 +222,46 @@ def finished(request, join_code):
|
|||||||
'is_host': is_host,
|
'is_host': is_host,
|
||||||
'participant_id': participant_id if participant else None
|
'participant_id': participant_id if participant else None
|
||||||
})
|
})
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def finished(request, join_code):
|
||||||
|
quiz_game = get_object_or_404(QuizGame, join_code=join_code)
|
||||||
|
|
||||||
|
if quiz_game.current_state != 'finished':
|
||||||
|
return redirect('play:lobby', join_code=join_code)
|
||||||
|
try:
|
||||||
|
game = QuizGame.objects.get(join_code=join_code)
|
||||||
|
# Get participants sorted by score
|
||||||
|
participants = QuizGameParticipant.objects.filter(quiz_game=quiz_game).order_by('-score')
|
||||||
|
|
||||||
|
|
||||||
|
# Get participant if exists
|
||||||
|
participant_id = request.COOKIES.get('participant_id')
|
||||||
|
participant = None
|
||||||
|
if participant_id:
|
||||||
|
participant = QuizGameParticipant.objects.filter(
|
||||||
|
quiz_game=quiz_game,
|
||||||
|
participant_id=participant_id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
is_host = False
|
||||||
|
if 'host_id' in request.COOKIES and request.COOKIES['host_id'] == quiz_game.host_id:
|
||||||
|
is_host = True
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'join_code': join_code,
|
||||||
|
'is_host': is_host,
|
||||||
|
'participants': participants,
|
||||||
|
'participant_id': participant_id if participant else None,
|
||||||
|
'rating_enabled': settings.QIVIP_CONFIG['ENABLE_RATING_SYSTEM']
|
||||||
|
}
|
||||||
|
return render(request, 'play/game/finished.html', context)
|
||||||
|
except QuizGame.DoesNotExist:
|
||||||
|
return redirect('home')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def question(request, join_code):
|
def question(request, join_code):
|
||||||
quiz_game = get_object_or_404(QuizGame, join_code=join_code)
|
quiz_game = get_object_or_404(QuizGame, join_code=join_code)
|
||||||
|
|||||||
35
django/templates/404.html
Normal file
35
django/templates/404.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="max-w-2xl mx-auto mt-20 p-6 bg-white shadow-xl rounded-2xl text-center dark:bg-transparent">
|
||||||
|
|
||||||
|
<div class="flex justify-center items-center gap-4">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
||||||
|
class="w-10 h-10 text-red-600">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" />
|
||||||
|
</svg>
|
||||||
|
<h1 class=" text-4xl font-extrabold text-red-600">404 Fehler</h1>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-6 flex justify-center">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||||
|
stroke="currentColor" class="w-24 h-24 text-gray-400">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
d="M15.182 16.318A4.486 4.486 0 0 0 12.016 15a4.486 4.486 0 0 0-3.198 1.318M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0ZM9.75 9.75c0 .414-.168.75-.375.75S9 10.164 9 9.75 9.168 9 9.375 9s.375.336.375.75Zm-.375 0h.008v.015h-.008V9.75Zm5.625 0c0 .414-.168.75-.375.75s-.375-.336-.375-.75.168-.75.375-.75.375.336.375.75Zm-.375 0h.008v.015h-.008V9.75Z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="text-2xl font-semibold text-gray-800 mb-2 dark:text-white ">Seite nicht gefunden</h2>
|
||||||
|
<p class="text-lg text-gray-600 mb-6 dark:text-white">Ups, die angeforderte Seite wurde nicht gefunden. Überprüfen Sie die URL oder kehren Sie zur Startseite zurück.</p>
|
||||||
|
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<a href="{% url 'homepage:home' %}"
|
||||||
|
class="bg-blue-600 hover:bg-blue-700 transition-colors text-white px-6 py-3 rounded-full text-lg font-semibold shadow-lg">
|
||||||
|
Zur Startseite
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
|
|
||||||
<div class="flex justify-center items-center mt-12">
|
<div class="flex justify-center items-center mt-12">
|
||||||
<div class="input-group p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md">
|
<div class="input-group p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md dark:bg-transparent! dark:text-white! ">
|
||||||
<div class="grid place-content-center h-120">
|
<div class="grid place-content-center h-full mb-4 flex-col items-center justify-between">
|
||||||
|
|
||||||
<h1 class="text-center m-4 text-3xl lg:text-6xl">Willkommen, <b>{{ request.user.username }}</b>!</h1>
|
<h1 class="text-center m-4 text-3xl lg:text-6xl">Willkommen, <b>{{ request.user.username }}</b>!</h1>
|
||||||
|
|
||||||
@@ -16,10 +16,28 @@
|
|||||||
</form>
|
</form>
|
||||||
<button class="text-center text-sm w-full mt-4 font-light text-blue-600"><a href="{% url 'accounts:password_change' %}">Passwort ändern</a></button>
|
<button class="text-center text-sm w-full mt-4 font-light text-blue-600"><a href="{% url 'accounts:password_change' %}">Passwort ändern</a></button>
|
||||||
<button class="text-center text-sm w-full mt-4 font-light text-red-600"><a href="{% url 'accounts:delete_account' %}">Account löschen</a></button>
|
<button class="text-center text-sm w-full mt-4 font-light text-red-600"><a href="{% url 'accounts:delete_account' %}">Account löschen</a></button>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="border-2 border-blue-600 p-6 rounded-xl shadow-inner bg-blue-50 flex flex-col gap-4 items-start mt-8 dark:bg-transparent">
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2 text-xl font-semibold text-blue-800 dark:text-blue-600">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 text-yellow-500">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 18.75h-9m9 0a3 3 0 0 1 3 3h-15a3 3 0 0 1 3-3m9 0v-3.375c0-.621-.503-1.125-1.125-1.125h-.871M7.5 18.75v-3.375c0-.621.504-1.125 1.125-1.125h.872m5.007 0H9.497m5.007 0a7.454 7.454 0 0 1-.982-3.172M9.497 14.25a7.454 7.454 0 0 0 .981-3.172M5.25 4.236c-.982.143-1.954.317-2.916.52A6.003 6.003 0 0 0 7.73 9.728M5.25 4.236V4.5c0 2.108.966 3.99 2.48 5.228M5.25 4.236V2.721C7.456 2.41 9.71 2.25 12 2.25c2.291 0 4.545.16 6.75.47v1.516M7.73 9.728a6.726 6.726 0 0 0 2.748 1.35m8.272-6.842V4.5c0 2.108-.966 3.99-2.48 5.228m2.48-5.492a46.32 46.32 0 0 1 2.916.52 6.003 6.003 0 0 1-5.395 4.972m0 0a6.726 6.726 0 0 1-2.749 1.35m0 0a6.772 6.772 0 0 1-3.044 0" />
|
||||||
|
</svg>
|
||||||
|
Erfolge
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="list-disc pl-6 text-base text-gray-700 dark:text-white">
|
||||||
|
<li><b>{{ my_quizzes_number }}</b> Quizze erstellt</li>
|
||||||
|
<li><b>{{ my_questions_number }}</b> Fragen insgesamt erstellt</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<span class="text-[clamp(0.6rem,5vw,1rem)] font-black overflow-x-auto mt-1 ml-0.75 text-blue-600 p-0.75 bg-white">qivip
|
<span class="text-[clamp(0.6rem,5vw,1rem)] font-black overflow-x-auto mt-1 ml-0.75 text-blue-600 p-0.75 bg-white dark:bg-transparent">qivip
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="grid place-content-center h-120 mt-12 mb-12 ">
|
<div class="grid place-content-center h-120 mt-12 mb-12 ">
|
||||||
<div class="w-80 p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90">
|
<div class="w-80 p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90">
|
||||||
<h2 class="text-2xl text-center p-4 font-black">Anmeldung</h2>
|
<h2 class="text-2xl text-center p-4 font-black dark:text-white">Anmeldung</h2>
|
||||||
<form class="space-y-4" method="post">
|
<form class="space-y-4" method="post">
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
<div class=" items-center text-red-600 font-black overflow-x-auto break-words text-center">
|
<div class=" items-center text-red-600 font-black overflow-x-auto break-words text-center">
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="grid place-content-center h-120 mt-12 mb-12">
|
<div class="grid place-content-center h-120 mt-12 mb-12">
|
||||||
|
|
||||||
<div class="w-80 p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90">
|
<div class="w-80 p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90">
|
||||||
<h2 class="text-2xl text-center p-4 font-black">Registrieren</h2>
|
<h2 class="text-2xl text-center p-4 font-black dark:text-white">Registrieren</h2>
|
||||||
|
|
||||||
<form class=" space-y-4" method="post">
|
<form class=" space-y-4" method="post">
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="de">
|
<html lang="de" class="dark:bg-gray-900">
|
||||||
<head>
|
<head>
|
||||||
<link rel="icon" type="image/png" href="{% static 'icons/favicon.png' %}">
|
<link rel="icon" type="image/png" href="{% static 'icons/favicon.png' %}">
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
@@ -75,5 +75,6 @@
|
|||||||
<style>html {
|
<style>html {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}</style>
|
}</style>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -4,9 +4,9 @@
|
|||||||
<div class="grid place-content-center md:h-screen h-150 w-full -z-50 top-0 p-4">
|
<div class="grid place-content-center md:h-screen h-150 w-full -z-50 top-0 p-4">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<h2 class="font-bold md:text-8xl text-6xl md:mb-8 text-blue-600">qivip</h2>
|
<h2 class="font-bold md:text-8xl text-6xl md:mb-8 text-blue-600">qivip</h2>
|
||||||
<h3 class="mt-4 italic font-extralight sm:text-4xl text-md">forever and forall</h3>
|
<h3 class="mt-4 italic font-light sm:text-4xl text-md bg-gradient-to-r from-pink-500 via-purple-600 to-blue-700 bg-clip-text text-transparent">weil Lernen auch Spaß <br> machen kann!</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid sm:grid-cols-3 place-items-stretch text-center mt-8 gap-4 p-4 border-3 bg-blue-100 border-blue-100 rounded-md">
|
<div class="grid sm:grid-cols-3 place-items-stretch text-center mt-8 gap-4 p-4 border-3 bg-blue-100 border-blue-100 rounded-md dark:bg-gray-900 dark:border-0">
|
||||||
<a class="qp-a-button bg-green-500 text-white" href="{% url 'play:join_game' %}">Teilnehmen</a>
|
<a class="qp-a-button bg-green-500 text-white" href="{% url 'play:join_game' %}">Teilnehmen</a>
|
||||||
<a class="qp-a-button bg-indigo-500 text-white" href="{% url 'library:overview_quiz' %}">Moderieren</a>
|
<a class="qp-a-button bg-indigo-500 text-white" href="{% url 'library:overview_quiz' %}">Moderieren</a>
|
||||||
<a class="qp-a-button bg-purple-500 text-white" href="{% url 'library:new_quiz' %}">Erstellen</a>
|
<a class="qp-a-button bg-purple-500 text-white" href="{% url 'library:new_quiz' %}">Erstellen</a>
|
||||||
@@ -22,16 +22,16 @@
|
|||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
{% if faqs %}
|
||||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-8 mb-6">
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-8 mb-6">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<h2 class="text-2xl font-bold text-gray-900">FAQs</h2>
|
<h2 class="text-2xl font-bold text-gray-900 dark:text-white">FAQs</h2>
|
||||||
<div class="h-0.5 flex-grow bg-gradient-to-r from-blue-600 to-transparent rounded-full"></div>
|
<div class="h-0.5 flex-grow bg-gradient-to-r from-blue-600 to-transparent rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="input-group !max-w-4xl tracking-wide">
|
<div class="input-group !max-w-4xl tracking-wide dark:!bg-gray-900 dark:!text-white">
|
||||||
<h1 class="font-black text-blue-600 flex justify-between gap-2 lg:text-lg">
|
<h1 class="font-black text-blue-600 flex justify-between gap-2 lg:text-lg">
|
||||||
|
|
||||||
|
|
||||||
@@ -42,126 +42,17 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% for faq in faqs %}
|
||||||
<div class="input-group mt-2.5 !max-w-4xl hover:!bg-gray-50">
|
<div class="input-group mt-2.5 !max-w-4xl hover:bg-gray-50 dark:!bg-gray-900 dark:!text-white ">
|
||||||
<details>
|
<details>
|
||||||
<summary class="flex justify-between cursor-pointer font-bold">Was ist qivip?
|
<summary class="flex justify-between cursor-pointer font-bold">{{ faq.question }}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
||||||
</svg>
|
</svg>
|
||||||
</summary>
|
</summary>
|
||||||
<p class="text-blue-600">qivip ist eine Webseite zum Lernen! Es können vor allem Quizze erstellt, bearbeitet, kopiert und auch gespielt werden. </p>
|
<p class="text-blue-600">{{ faq.answer }}</p>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
{% endfor %}
|
||||||
<div class="input-group mt-2.5 !max-w-4xl hover:!bg-gray-50">
|
{% endif %}
|
||||||
<details>
|
|
||||||
<summary class="flex justify-between cursor-pointer font-bold">Was sind die Vorteile von qivip?
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
|
||||||
</svg>
|
|
||||||
</summary>
|
|
||||||
<p class="text-blue-600">
|
|
||||||
Einige Vorteile von qivip:
|
|
||||||
<br>
|
|
||||||
- Sie können Quizze moderieren ohne Account (siehe wie man Quizze mit mehreren Personen gemeinsam spielt)
|
|
||||||
<br>
|
|
||||||
- alle öffentlichen Quizze können auch ohne Account gespielt werden
|
|
||||||
<br>
|
|
||||||
- qivip ist zu 100% kostenlos
|
|
||||||
<br>
|
|
||||||
- es gibt keine Werbung
|
|
||||||
<br>
|
|
||||||
- qivip ist Open Source
|
|
||||||
</p>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="input-group mt-2.5 !max-w-4xl hover:!bg-gray-50">
|
|
||||||
<details>
|
|
||||||
<summary class="flex justify-between cursor-pointer font-bold">Ist qivip kostenlos?
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
|
||||||
</svg>
|
|
||||||
</summary>
|
|
||||||
<p class="text-blue-600">Ja! qivip ist zu 100% kostenlos und es gibt keine versteckten Kosten.</p>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="input-group mt-2.5 !max-w-4xl hover:!bg-gray-50">
|
|
||||||
<details>
|
|
||||||
<summary class="flex justify-between cursor-pointer font-bold">Muss ich mich bei qivip registrieren, wenn ich ein Quiz spielen möchte?
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
|
||||||
</svg>
|
|
||||||
</summary>
|
|
||||||
<p class="text-blue-600">Nein! qivip ist so ausgelegt, dass man auch ohne Account alle öffentlichen Quizze spielen kann.</p>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="input-group mt-2.5 !max-w-4xl hover:!bg-gray-50">
|
|
||||||
<details>
|
|
||||||
<summary class="flex justify-between cursor-pointer font-bold">Kann ich ein Quiz von qivip auch alleine spielen?
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
|
||||||
</svg>
|
|
||||||
</summary>
|
|
||||||
<p class="text-blue-600">Ja! Gehen Sie zur Bibliothek und klicken Sie auf den Button "spielen" (eines von Ihnen ausgewählten Quizzes). Wählen Sie anschließend bei den Spielmodi einfach den Lernmodus aus.</p>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
<div class="input-group mt-2.5 !max-w-4xl hover:!bg-gray-50">
|
|
||||||
<details>
|
|
||||||
<summary class="flex justify-between cursor-pointer font-bold">Wie kann ich ein Quiz erstellen?
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
|
||||||
</svg>
|
|
||||||
</summary>
|
|
||||||
<p class="text-blue-600">Wichtig: Für diese Funktion müssen Sie angemeldet sein. Gehen Sie dafür auf die Startseite und klicken Sie auf "Erstellen". Nun wird Ihnen ein Formular angezeigt, dass Sie dann ausfüllen.
|
|
||||||
Anschließend können Sie Fragen zu dem Quiz hinzufügen, indem Sie auf den Button eines Fragetyps klicken. </p>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="input-group mt-2.5 !max-w-4xl hover:!bg-gray-50">
|
|
||||||
<details>
|
|
||||||
<summary class="flex justify-between cursor-pointer font-bold">Wie kann ich mit mehreren Personen ein Quiz gemeinsam spielen?
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
|
||||||
</svg>
|
|
||||||
</summary>
|
|
||||||
<p class="text-blue-600">
|
|
||||||
Wenn man ein Quiz mit mehreren Personen spielt, gibt es sowohl einen Moderator als auch die Teilnehmer.
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
<b>Moderator: </b>Der Moderator selbst spielt nicht mit. Gehen Sie entweder auf die Startseite und klicken Sie auf "Moderieren" oder klicken einfach auf "spielen" (eines von Ihnen ausgewählten Quizzes) und dann auf Moderiermodus.
|
|
||||||
Der Moderator kann das Spiel, wenn die Teilnehmer da sind, starten.
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
<b>Teilnehmer: </b>Gehen Sie auf die Startseite und klicken Sie auf "Teilnehmen" und geben Sie dann den beim Moderator angegebenen Zahlencode ein. Anschließlich können Sie noch einen Anzeigenamen eingeben.
|
|
||||||
</p>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="input-group mt-2.5 !max-w-4xl hover:!bg-gray-50">
|
|
||||||
<details>
|
|
||||||
<summary class="flex justify-between cursor-pointer font-bold">Wo steht unser Server?
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
|
||||||
</svg>
|
|
||||||
</summary>
|
|
||||||
<p class="text-blue-600">Unser Server befindet sich in Deutschland, genauer gesagt in Nürnberg. </p>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="input-group mt-2.5 !max-w-4xl hover:!bg-gray-50">
|
|
||||||
<details>
|
|
||||||
<summary class="flex justify-between cursor-pointer font-bold">Wer steckt hinter qivip?
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
|
||||||
</svg>
|
|
||||||
</summary>
|
|
||||||
<p class="text-blue-600">Wir sind eine kleine Gruppe von Schülern, die sich im Rahmen eines Enrichmenten Projektes zusammengefunden hat. </p>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
{% block content%}
|
{% block content%}
|
||||||
|
|
||||||
<div class="flex justify-center items-center mt-12">
|
<div class="flex justify-center items-center mt-12">
|
||||||
<div class="input-group p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md">
|
<div class="input-group p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md dark:!bg-transparent dark:!text-white ">
|
||||||
<div class="grid place-content-center h-120">
|
<div class="grid place-content-center h-120">
|
||||||
|
|
||||||
<h1 class="text-center m-4 text-3xl lg:text-6xl">Impressum</b></h1>
|
<h1 class="text-center m-4 text-3xl lg:text-6xl">Impressum</b></h1>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<span class="text-[clamp(0.6rem,5vw,1rem)] font-black overflow-x-auto mt-1 ml-0.75 text-blue-600 p-0.75 bg-white">qivip
|
<span class="text-[clamp(0.6rem,5vw,1rem)] font-black overflow-x-auto mt-1 ml-0.75 text-blue-600 p-0.75 bg-white dark:bg-transparent ">qivip
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{% block content%}
|
{% block content%}
|
||||||
<div class="flex justify-center items-center mt-12 ">
|
<div class="flex justify-center items-center mt-12 ">
|
||||||
<div class="input-group p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md">
|
<div class="input-group p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md dark:!bg-transparent dark:!text-white">
|
||||||
<div class="grid place-content-center h-120">
|
<div class="grid place-content-center h-120">
|
||||||
|
|
||||||
<h1 class="text-center m-4 text-3xl lg:text-6xl">Datenschutz-</br>erklärung</h1>
|
<h1 class="text-center m-4 text-3xl lg:text-6xl">Datenschutz-</br>erklärung</h1>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<span class="text-[clamp(0.6rem,5vw,1rem)] font-black overflow-x-auto mt-1 ml-0.75 text-blue-600 p-0.75 bg-white">qivip
|
<span class="text-[clamp(0.6rem,5vw,1rem)] font-black overflow-x-auto mt-1 ml-0.75 text-blue-600 p-0.75 bg-white dark:!bg-transparent ">qivip
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,15 +3,15 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mx-auto px-4">
|
<div class="container mx-auto px-4">
|
||||||
<div class="max-w-lg mx-auto mt-10">
|
<div class="max-w-lg mx-auto mt-10">
|
||||||
<div class="bg-white rounded-lg shadow-md p-6 border-blue-600 border-2 rounded-xl shadow-md">
|
<div class="bg-white rounded-lg shadow-md p-6 border-blue-600 border-2 rounded-xl shadow-md dark:text-white dark:bg-transparent">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<svg class="mx-auto h-12 w-12 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="mx-auto h-12 w-12 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<h2 class="mt-4 text-xl font-bold text-gray-900">Löschen bestätigen</h2>
|
<h2 class="mt-4 text-xl font-bold text-gray-900 dark:text-white">Löschen bestätigen</h2>
|
||||||
|
|
||||||
<p class="mt-2 text-sm text-gray-600">
|
<p class="mt-2 text-sm text-gray-600 dark:text-white">
|
||||||
{% if object.quiz_id %}
|
{% if object.quiz_id %}
|
||||||
Möchten Sie die Frage "{{ object.data.question }}" wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.
|
Möchten Sie die Frage "{{ object.data.question }}" wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@@ -4,21 +4,21 @@
|
|||||||
|
|
||||||
<div class="container mx-auto px-4">
|
<div class="container mx-auto px-4">
|
||||||
|
|
||||||
<div class="flex flex-wrap space-y-2 items-center justify-between mb-6">
|
<div class="flex flex-wrap space-y-2 items-center justify-between mb-6 dark:text-white">
|
||||||
<h1 class="text-2xl font-bold mr-4 ">{{ quiz.name }}</h1>
|
<h1 class="text-2xl font-bold mr-4 dark:text-white ">{{ quiz.name }}</h1>
|
||||||
|
|
||||||
<div class=" flex flex-wrap space-x-2 ">
|
<div class=" flex flex-wrap space-x-2 ">
|
||||||
|
|
||||||
<div class="flex flex-wrap">
|
<div class="flex flex-wrap">
|
||||||
{% if quiz.user_id == request.user %}
|
{% if quiz.user_id == request.user %}
|
||||||
<a href="{% url 'library:edit_quiz' quiz.id %}" class=" text-white px-2 py-2 rounded-md text-sm lg:text-lg hover:scale-110 transition-colors">
|
<a href="{% url 'library:edit_quiz' quiz.id %}" class=" text-white px-2 py-2 rounded-md text-sm lg:text-lg hover:scale-110 transition-colors">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7 text-gray-600">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7 text-gray-600 dark:text-white">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
<a href="{% url 'library:delete_quiz' quiz.id %}" class=" text-white px-2 py-2 rounded-md text-sm lg:text-lg hover:scale-110 transition-colors">
|
<a href="{% url 'library:delete_quiz' quiz.id %}" class=" text-white px-2 py-2 rounded-md text-sm lg:text-lg hover:scale-110 transition-colors">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7 text-gray-600">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7 text-gray-600 dark:text-white">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
@@ -54,13 +54,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if quiz.description %}
|
{% if quiz.description %}
|
||||||
<p class="text-gray-600 mb-4">{{ quiz.description }}</p>
|
<p class="text-gray-600 mb-4 dark:text-gray-400">{{ quiz.description }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="flex justify-end mb-4">
|
<div class="flex justify-end mb-4">
|
||||||
{% if detail == True %}
|
{% if detail == True %}
|
||||||
|
|
||||||
<a href="{% url 'library:detail_quiz' quiz.id %}?show_answers=false">
|
<a href="{% url 'library:detail_quiz' quiz.id %}?show_answers=false">
|
||||||
<div class="flex items-center mr-2">
|
<div class="flex items-center mr-2 dark:text-white">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" />
|
||||||
</svg>
|
</svg>
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
<a href="{% url 'library:detail_quiz' quiz.id %}?show_answers=true">
|
<a href="{% url 'library:detail_quiz' quiz.id %}?show_answers=true">
|
||||||
<div class="flex items-center mr-2">
|
<div class="flex items-center mr-2 dark:text-white">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||||
@@ -85,10 +85,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="bg-white rounded-lg shadow-md border-blue-600 border-2 rounded-xl shadow-md">
|
<div class="bg-white rounded-lg shadow-md border-blue-600 border-2 rounded-xl shadow-md dark:!bg-transparent dark:text-white">
|
||||||
<div class="border-b border-gray-200 p-4">
|
<div class="border-b border-gray-200 p-4">
|
||||||
<div class="flex justify-between items-center flex-wrap">
|
<div class="flex justify-between items-center flex-wrap">
|
||||||
<h2 class="text-xl font-semibold">Fragen</h2>
|
<h2 class="text-xl font-semibold">Fragen
|
||||||
|
{% for question in questions %}{% if forloop.last %}({{ forloop.counter }}) {% endif %} {% endfor %}
|
||||||
|
</h2>
|
||||||
<div class="flex space-x-2 flex-wrap">
|
<div class="flex space-x-2 flex-wrap">
|
||||||
{% if quiz.user_id == request.user %}
|
{% if quiz.user_id == request.user %}
|
||||||
<a href="{% url 'library:new_question' %}?type=input&quiz_id={{ quiz.id }}"
|
<a href="{% url 'library:new_question' %}?type=input&quiz_id={{ quiz.id }}"
|
||||||
@@ -119,7 +121,10 @@
|
|||||||
<div class="divide-y divide-gray-200">
|
<div class="divide-y divide-gray-200">
|
||||||
{% for question in questions %}
|
{% for question in questions %}
|
||||||
|
|
||||||
<div class="w-full rounded-xl p-4 hover:bg-gray-50">
|
|
||||||
|
|
||||||
|
<div class="w-full rounded-xl p-4 hover:bg-gray-50 dark:hover:bg-[#2a2f3a] dark:text-white">
|
||||||
|
<p>{{ forloop.counter }}.</p>
|
||||||
{% if quiz.user_id == request.user %} <a class="block flex h-full w-full" href="{% url 'library:edit_question' question.id %}" > {% endif %}
|
{% if quiz.user_id == request.user %} <a class="block flex h-full w-full" href="{% url 'library:edit_question' question.id %}" > {% endif %}
|
||||||
<div class="flex justify-between items-start">
|
<div class="flex justify-between items-start">
|
||||||
|
|
||||||
@@ -134,44 +139,62 @@
|
|||||||
{% if detail %}
|
{% if detail %}
|
||||||
|
|
||||||
{% if question.data.type == 'multiple_choice' %}
|
{% if question.data.type == 'multiple_choice' %}
|
||||||
|
<div class="w-full gap-4 md:flex justify-between ">
|
||||||
<ul class="space-y-1 ">
|
<ul class="space-y-1 ">
|
||||||
{% for option in question.data.options %}
|
{% for option in question.data.options %}
|
||||||
|
|
||||||
|
|
||||||
<li class="flex items-center text-sm ">
|
<li class="flex items-center text-sm ">
|
||||||
|
|
||||||
{% if option.is_correct %}
|
{% if option.is_correct %}
|
||||||
<svg class="h-4 w-4 text-green-500 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="h-4 w-4 text-green-500 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="font-medium text-green-700">{{ option.value }}</span>
|
<span class="font-medium text-green-700">{{ option.value }}</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<svg class="h-4 w-4 text-gray-400 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="h-4 w-4 text-gray-400 mr-1.5 dark:text-white " fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 12H6"/>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 12H6"/>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="text-gray-600">{{ option.value }}</span>
|
<span class="text-gray-600 dark:text-white">{{ option.value }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
{% if question.image.image.url %}
|
||||||
|
<img src="{{ question.image.image.url }}" alt="Bild der Frage" class="w-[200px] rounded-lg shadow-md border-blue-600 border-2 rounded-xl shadow-md object-contain mt-4 md:mt-0" />
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% elif question.data.type == 'input' %}
|
{% elif question.data.type == 'input' %}
|
||||||
|
<div class="w-full gap-4 md:flex justify-between ">
|
||||||
<ul class="space-y-1 ">
|
<ul class="space-y-1 ">
|
||||||
{% for option in question.data.options %}
|
{% for option in question.data.options %}
|
||||||
<li class="flex items-center text-sm">
|
<li class="flex items-center text-sm">
|
||||||
<svg class="h-4 w-4 text-green-500 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="h-4 w-4 text-green-500 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="font-medium text-green-700">{{ option.value }}</span>
|
<span class="font-medium text-green-700 dark:text-white">{{ option.value }}</span>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
{% if question.image.image.url %}
|
||||||
|
<img src="{{ question.image.image.url }}" alt="Bild der Frage" class="w-[200px] rounded-lg shadow-md border-blue-600 border-2 rounded-xl shadow-md object-contain mt-4 md:mt-0" />
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
<div class="w-full gap-4 md:flex justify-between ">
|
||||||
{% for option in question.data.options %}
|
{% for option in question.data.options %}
|
||||||
{% if option.is_correct %}
|
{% if option.is_correct %}
|
||||||
<p class="text-sm">
|
<p class="text-sm">
|
||||||
<span class="text-gray-500">Richtige Antwort:</span>
|
<span class="text-gray-500 dark:text-white">Richtige Antwort:</span>
|
||||||
<span class="ml-1 font-medium {% if option.value == "Wahr" %} text-green-700 {% else %}text-red-700{% endif %}">{{ option.value }}</span>
|
<span class="ml-1 font-medium {% if option.value == "Wahr" %} text-green-700 {% else %}text-red-700{% endif %}">{{ option.value }}</span>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if question.image.image.url %}
|
||||||
|
<img src="{{ question.image.image.url }}" alt="Bild der Frage" class="w-[200px] rounded-lg shadow-md border-blue-600 border-2 rounded-xl shadow-md object-contain mt-4 md:mt-0" />
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@@ -186,7 +209,7 @@
|
|||||||
<a href=" {% url 'library:delete_question' question.id %}"
|
<a href=" {% url 'library:delete_question' question.id %}"
|
||||||
class=" text-red-700 px-4 py-1 rounded hover:scale-110 ">
|
class=" text-red-700 px-4 py-1 rounded hover:scale-110 ">
|
||||||
{% if quiz.user_id == request.user %}
|
{% if quiz.user_id == request.user %}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-7 text-gray-600">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="dark:text-white size-7 text-gray-600">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||||
</svg>
|
</svg>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -213,29 +236,55 @@
|
|||||||
|
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
{% if quiz.base_quiz %}
|
{% if quiz.base_quiz %}
|
||||||
<p class="text-gray-600 mt-2 ">Bearbeitung:<span class="text-blue-600 font-bold"> <a href="{% url 'library:overview_quiz' %}?filter=1&user={{ quiz.user_id }}">{{ quiz.user_id }}</a></span></p>
|
<p class="text-gray-600 mt-2 dark:text-white">Bearbeitung:<span class="text-blue-600 font-bold"> <a href="{% url 'library:overview_quiz' %}?filter=1&user={{ quiz.user_id }}">{{ quiz.user_id }}</a></span></p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="text-gray-600 mt-2 ">Autor:<span class="text-blue-600 font-bold"> <a href="{% url 'library:overview_quiz' %}?filter=1&user={{ quiz.user_id }}">{{ quiz.user_id }}</a></span></p>
|
<p class="text-gray-600 mt-2 dark:text-white">Autor:<span class="text-blue-600 font-bold"> <a href="{% url 'library:overview_quiz' %}?filter=1&user={{ quiz.user_id }}">{{ quiz.user_id }}</a></span></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
{% if quiz.base_quiz %}
|
{% if quiz.base_quiz %}
|
||||||
<p class="text-gray-600 ">Kopie von: <a href="{% url 'library:detail_quiz' quiz.base_quiz.id %}"><span class="text-blue-600 font-bold">{{ quiz.base_quiz}}</span></a></p>
|
<p class="text-gray-600 dark:text-white ">Kopie von: <a href="{% url 'library:detail_quiz' quiz.base_quiz.id %}"><span class="text-blue-600 font-bold">{{ quiz.base_quiz}}</span></a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
{% if quiz.base_quiz %}
|
{% if quiz.base_quiz %}
|
||||||
<p class="text-gray-600 ">Autor:<span class="text-blue-600 font-bold"> <a href="{% url 'library:overview_quiz' %}?filter=1&user={{ quiz.base_quiz.user_id }}">{{ quiz.base_quiz.user_id }}</a></span></p>
|
<p class="text-gray-600 dark:text-white">Autor:<span class="text-blue-600 font-bold"> <a href="{% url 'library:overview_quiz' %}?filter=1&user={{ quiz.base_quiz.user_id }}">{{ quiz.base_quiz.user_id }}</a></span></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end">
|
<div class="flex flex-col max-w-full">
|
||||||
|
<p class="text-gray-600 mt-2 dark:text-white ">Credits: </p>
|
||||||
{% if quiz.credits %}
|
{% if quiz.credits %}
|
||||||
<p class="text-gray-600 mb-2">Credits:<span class="text-blue-600 font-bold"> {{ quiz.credits }}</span></p>
|
<p class="text-blue-500 mb-2 w-full break-words dark:text-gray-400 ">
|
||||||
|
<span class="break-words italic">{{ quiz.credits }}</span>
|
||||||
|
<span class="font-normal break-words text-gray-600 dark:text-white">(Credits für das Quiz)</span>
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="text-gray-500 dark:text-gray-400 ">Keine Credits für das Quizformular vorhanden!</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col max-w-full">
|
||||||
|
<ul class="space-y-2">
|
||||||
|
{% regroup questions by credits as grouped_credits %}
|
||||||
|
{% if grouped_credits|length == 1 and not grouped_credits.0.grouper %}
|
||||||
|
<li class="text-gray-500 dark:text-gray-400 ">Keine Credits für die Fragen vorhanden!</li>
|
||||||
|
{% else %}
|
||||||
|
{% for question in questions %}
|
||||||
|
{% if question.credits %}
|
||||||
|
<li class="text-blue-500 mb-2 w-full break-words break-words dark:text-gray-400 ">
|
||||||
|
<span class="italic">{{ question.credits }}</span>
|
||||||
|
<span class="font-normal break-words text-gray-600 dark:text-white">(Frage: {{ forloop.counter }})</span>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="input-group border-blue-600 border-2 rounded-xl shadow-md mt-12">
|
<style>
|
||||||
|
.dark label {
|
||||||
|
color: white!important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="dark input-group border-blue-600 border-2 rounded-xl shadow-md mt-12 dark:text-white! dark:bg-transparent!">
|
||||||
<form method="post" enctype="multipart/form-data">
|
<form method="post" enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
@@ -15,7 +22,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<div>
|
<div>
|
||||||
<label class="font-bold" for="quiz_image">Bild:</label>
|
<label class="font-bold" for="quiz_image">Bild:</label>
|
||||||
<input class="bg-blue-200 p-2 m-2 rounded-lg border-2 border-blue-400" type="file" name="quiz_image" id="quiz_image">
|
<input class="max-w-full bg-blue-200 p-2 m-2 rounded-lg border-2 border-blue-400 dark:bg-transparent" type="file" name="quiz_image" id="quiz_image">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-center text-gray-600 text-sm dislay-flex align-bottom">
|
<div class="text-center text-gray-600 text-sm dislay-flex align-bottom">
|
||||||
|
|||||||
145
django/templates/library/head.html
Normal file
145
django/templates/library/head.html
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block extra_css %}
|
||||||
|
<style>
|
||||||
|
|
||||||
|
|
||||||
|
.custom-outline {
|
||||||
|
-webkit-text-stroke: 0.2px rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
<div class="container mx-auto px-4 py-4 flex justify-between items-center">
|
||||||
|
<button id="filterButton" class="dark:text-white dark:hover:bg-[#2a2f3a] p-2 hover:bg-gray-100 rounded-lg transition-colors duration-200 flex items-center gap-2 text-gray-700">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
|
||||||
|
</svg>
|
||||||
|
<span>Filter</span>
|
||||||
|
</button>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<a href="{% url link %}" class="dark:bg-transparent dark:text-white dark:hover:bg-[#2a2f3a] inline-flex items-center px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors duration-200">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||||
|
</svg>
|
||||||
|
Zurücksetzen
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'library:new_quiz' %}" class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors duration-200">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||||
|
</svg>
|
||||||
|
Neues Quiz
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="filterPanel" class="container mx-auto px-4 {% if request.GET.filter == '1' %}block{% else %}hidden{% endif %}">
|
||||||
|
<div class="bg-white rounded-xl shadow-lg p-6 border border-gray-200 dark:bg-transparent dark:text-white ">
|
||||||
|
<form action="{% url link %}" method="get" class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
|
<input type="hidden" name="filter" id="filter-input">
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<input type="checkbox" name="use_min_amount_questions" id="use_min_amount_questions" {% if form.use_min_amount_questions.value %}checked{% endif %}>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-white">minimale Anzahl an Fragen</label>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
name="min_amount_questions"
|
||||||
|
id="id_min_amount_questions"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
step="1"
|
||||||
|
value="{{ form.min_amount_questions.value|default_if_none:0 }}"
|
||||||
|
class="w-full accent-blue-600 dark:text-white"
|
||||||
|
oninput="document.getElementById('min_amount_value').textContent = this.value + ' Frage(n)'"
|
||||||
|
{% if not form.use_min_amount_questions.value %}disabled{% endif %}
|
||||||
|
>
|
||||||
|
|
||||||
|
<span id="min_amount_value" class="text-sm font-semibold text-gray-800 dark:text-white">
|
||||||
|
{{ form.min_amount_questions.value|default_if_none:0 }} Frage(n)
|
||||||
|
</span>
|
||||||
|
<br>
|
||||||
|
<span class="text-xs text-gray-600 dark:text-white"> Quizze anderer User werden erst ab min. 1 Frage angezeigt.</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<input type="checkbox" name="use_max_amount_questions" id="use_max_amount_questions" {% if form.use_max_amount_questions.value %}checked{% endif %}>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-white">maximale Anzahl an Fragen</label>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
name="max_amount_questions"
|
||||||
|
id="id_max_amount_questions"
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
step="1"
|
||||||
|
value="{{ form.max_amount_questions.value|default_if_none:100 }}"
|
||||||
|
class="w-full accent-blue-600"
|
||||||
|
oninput="document.getElementById('max_amount_value').textContent = this.value+' Frage(n)'"
|
||||||
|
{% if not form.use_max_amount_questions.value %}disabled{% endif %}
|
||||||
|
>
|
||||||
|
|
||||||
|
<span id="max_amount_value" class="text-sm font-semibold text-gray-800 dark:text-white">
|
||||||
|
{{ form.max_amount_questions.value|default_if_none:100 }} Frage(n)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-white">veröffentlicht von User</label>
|
||||||
|
<input type="text" name="user" class="border-2 border-gray-300 rounded-lg p-2 w-full dark:text-white" id="id_user" value="{{ form.user.value|default_if_none:'' }}">
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-white">Kategorie</label>
|
||||||
|
{{ form.categories }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-white">Suche</label>
|
||||||
|
{{ form.search }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="md:col-span-3 flex justify-end">
|
||||||
|
<button
|
||||||
|
type="submit" class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors duration-200">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"></path>
|
||||||
|
</svg>
|
||||||
|
Filtern
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
|
|
||||||
|
const checkbox = document.getElementById('use_min_amount_questions');
|
||||||
|
const slider = document.getElementById('id_min_amount_questions');
|
||||||
|
|
||||||
|
const checkbox_max = document.getElementById('use_max_amount_questions');
|
||||||
|
const slider_max = document.getElementById('id_max_amount_questions');
|
||||||
|
|
||||||
|
checkbox.addEventListener('change', () => {
|
||||||
|
slider.disabled = !checkbox.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
checkbox_max.addEventListener('change', () => {
|
||||||
|
slider_max.disabled = !checkbox_max.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
672
django/templates/library/overview_quiz(old).html
Normal file
672
django/templates/library/overview_quiz(old).html
Normal file
@@ -0,0 +1,672 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
<!-- Die gesamte Seite wird eigentlich nicht mehr genutzt. WICHTIG: ggf. kann Code aber hiervon noch genutzt werden. -->
|
||||||
|
{% block extra_css %}
|
||||||
|
<style>
|
||||||
|
|
||||||
|
|
||||||
|
.custom-outline {
|
||||||
|
-webkit-text-stroke: 0.2px rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="container mx-auto px-4 py-4 flex justify-between items-center">
|
||||||
|
<button id="filterButton" class="p-2 hover:bg-gray-100 rounded-lg transition-colors duration-200 flex items-center gap-2 text-gray-700">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
|
||||||
|
</svg>
|
||||||
|
<span>Filter</span>
|
||||||
|
</button>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<a href="{% url 'library:overview_quiz' %}" class="inline-flex items-center px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors duration-200">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||||
|
</svg>
|
||||||
|
Zurücksetzen
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'library:new_quiz' %}" class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors duration-200">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||||
|
</svg>
|
||||||
|
Neues Quiz
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="filterPanel" class="container mx-auto px-4">
|
||||||
|
<div class="bg-white rounded-xl shadow-lg p-6 border border-gray-200">
|
||||||
|
<form action="{% url 'library:overview_quiz' %}" method="get" class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
|
<input type="hidden" name="filter" value="1">
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700">minimale Anzahl an Fragen</label>
|
||||||
|
<input type="number" name="min_amount_questions" class="border-2 border-gray-300 rounded-lg p-2 w-full" min="1" id="id_min_amount_questions" value="{{ form.min_amount_questions.value|default_if_none:'' }}">
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700">maximale Anzahl an Fragen</label>
|
||||||
|
<input type="number" name="max_amount_questions" class="border-2 border-gray-300 rounded-lg p-2 w-full" min="1" id="id_max_amount_questions" value="{{ form.max_amount_questions.value|default_if_none:'' }}">
|
||||||
|
</div>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700">veröffentlicht von User</label>
|
||||||
|
<input type="text" name="user" class="border-2 border-gray-300 rounded-lg p-2 w-full" id="id_user" value="{{ form.user.value|default_if_none:'' }}">
|
||||||
|
</div>
|
||||||
|
<div class="md:col-span-3 flex justify-end">
|
||||||
|
<button type="submit" class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors duration-200">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"></path>
|
||||||
|
</svg>
|
||||||
|
Filtern
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-8 mb-6">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<h2 id="my-quizzes" class="text-2xl font-bold text-gray-900">Meine Quizze</h2>
|
||||||
|
<div class="h-0.5 flex-grow bg-gradient-to-r from-blue-600 to-transparent rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 auto-rows-fr">
|
||||||
|
{% for quiz in my_quizzes %}
|
||||||
|
<article class="relative min-h-[20rem] rounded-xl shadow-lg overflow-hidden bg-white flex flex-col">
|
||||||
|
<!-- Image Section (Top) -->
|
||||||
|
<div class="h-48 w-full relative flex-shrink-0">
|
||||||
|
{% if quiz.image %}
|
||||||
|
<div class="relative w-full h-full inset-0 bg-cover bg-center">
|
||||||
|
<!-- Hintergrundbild -->
|
||||||
|
<div class="absolute inset-0 bg-cover bg-center"
|
||||||
|
style="background-image: url({{ quiz.image.image.url }});">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class="h-full bg-gradient-to-r from-blue-500 to-blue-600 flex items-center justify-center font-black text-white text-4xl px-4 overflow-auto break-words hyphens-auto ">{{ quiz.name }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
{% if quiz.id not in favorite_quiz_ids %}
|
||||||
|
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg">
|
||||||
|
|
||||||
|
<a href="{% url 'library:favorite_quiz' quiz.pk %}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-black size-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg">
|
||||||
|
<a href="{% url 'library:favorite_quiz' quiz.pk %}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-yellow-400 size-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Content Section (Bottom) -->
|
||||||
|
<div class="flex-grow bg-white p-4 flex flex-col gap-3">
|
||||||
|
<!-- Title -->
|
||||||
|
<h2 class="text-xl font-bold text-gray-900 break-words mb-2">
|
||||||
|
<a href="{% url 'library:detail_quiz' quiz.id %}" class="hover:text-blue-600 transition-colors">{{ quiz.name }}</a>
|
||||||
|
</h2>
|
||||||
|
<!-- Description -->
|
||||||
|
<p class="text-sm text-gray-700 break-words mb-3">{{ quiz.description }}</p>
|
||||||
|
|
||||||
|
<!-- Quiz Info Grid -->
|
||||||
|
<div class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
|
||||||
|
<!-- Difficulty -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800">{{ quiz.difficulty }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Questions Count -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800">{{ quiz.questions.count }} Fragen</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800">{{ quiz.status }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Rating -->
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
{% if quiz.rating_count > 0 %}
|
||||||
|
{% for i in '12345'|make_list %}
|
||||||
|
{% if forloop.counter <= quiz.average_rating|floatformat:0|add:0 %}
|
||||||
|
<span class="text-yellow-500 text-base">★</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-gray-300 text-base">★</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<span class="text-gray-600 text-sm">({{ quiz.rating_count }})</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-gray-600 text-sm">Noch keine Bewertungen</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Authors -->
|
||||||
|
{% if quiz.authors.all %}
|
||||||
|
<div class="flex items-center gap-2 text-sm mt-2">
|
||||||
|
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-600">
|
||||||
|
{% for author in quiz.authors.all %}
|
||||||
|
{{ author.username }}{% if not forloop.last %}, {% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="flex justify-between items-center gap-2 mt-3 border-t pt-3">
|
||||||
|
{% if quiz.questions.count != 0 %}
|
||||||
|
<a href="{% url 'play:create_game' quiz.id %}"
|
||||||
|
class="px-3 py-1.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors duration-200 flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
Spielen
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
Fürs Spielen ist min. 1 Frage nötig!
|
||||||
|
{% endif %}
|
||||||
|
<div class="flex gap-1">
|
||||||
|
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% if quiz.user_id == request.user %}
|
||||||
|
<a href="{% url 'library:edit_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'library:delete_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors duration-200">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination für Meine Quizze -->
|
||||||
|
{% if my_quizzes.paginator.num_pages > 1 %}
|
||||||
|
<div class="flex justify-center space-x-2 mt-6 mb-8">
|
||||||
|
{% if my_quizzes.has_previous %}
|
||||||
|
<a href="?my_page={{ my_quizzes.previous_page_number }}{% if request.GET.all_page %}&all_page={{ request.GET.all_page }}{% endif %}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}"
|
||||||
|
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<span class="px-3 py-1 text-gray-600">Seite {{ my_quizzes.number }} von {{ my_quizzes.paginator.num_pages }}</span>
|
||||||
|
|
||||||
|
{% if my_quizzes.has_next %}
|
||||||
|
<a href="?my_page={{ my_quizzes.next_page_number }}{% if request.GET.all_page %}&all_page={{ request.GET.all_page }}{% endif %}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}"
|
||||||
|
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-8 mb-6">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<h2 id="my-quizzes" class="text-2xl font-bold text-gray-900">Meine Favoriten</h2>
|
||||||
|
<div class="h-0.5 flex-grow bg-gradient-to-r from-blue-600 to-transparent rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 auto-rows-fr">
|
||||||
|
{% for quiz in favorite_quizzes %}
|
||||||
|
<article class="relative min-h-[20rem] rounded-xl shadow-lg overflow-hidden bg-white flex flex-col">
|
||||||
|
<!-- Image Section (Top) -->
|
||||||
|
<div class="h-48 w-full relative flex-shrink-0">
|
||||||
|
{% if quiz.image %}
|
||||||
|
<div class="relative w-full h-full inset-0 bg-cover bg-center">
|
||||||
|
<!-- Hintergrundbild -->
|
||||||
|
<div class="absolute inset-0 bg-cover bg-center"
|
||||||
|
style="background-image: url({{ quiz.image.image.url }});">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class="h-full bg-gradient-to-r from-blue-500 to-blue-600 flex items-center justify-center font-black text-white text-4xl px-4 overflow-auto break-words hyphens-auto ">{{ quiz.name }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
{% if quiz.favorite == False %}
|
||||||
|
|
||||||
|
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg">
|
||||||
|
|
||||||
|
<a href="{% url 'library:favorite_quiz' quiz.pk %}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-black size-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg">
|
||||||
|
<a href="{% url 'library:favorite_quiz' quiz.pk %}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-yellow-400 size-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Content Section (Bottom) -->
|
||||||
|
<div class="flex-grow bg-white p-4 flex flex-col gap-3">
|
||||||
|
<!-- Title -->
|
||||||
|
<h2 class="text-xl font-bold text-gray-900 break-words mb-2">
|
||||||
|
<a href="{% url 'library:detail_quiz' quiz.id %}" class="hover:text-blue-600 transition-colors">{{ quiz.name }}</a>
|
||||||
|
</h2>
|
||||||
|
<!-- Description -->
|
||||||
|
<p class="text-sm text-gray-700 break-words mb-3">{{ quiz.description }}</p>
|
||||||
|
|
||||||
|
<!-- Quiz Info Grid -->
|
||||||
|
<div class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
|
||||||
|
<!-- Difficulty -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800">{{ quiz.difficulty }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Questions Count -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800">{{ quiz.questions.count }} Fragen</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800">{{ quiz.status }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Rating -->
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
{% if quiz.rating_count > 0 %}
|
||||||
|
{% for i in '12345'|make_list %}
|
||||||
|
{% if forloop.counter <= quiz.average_rating|floatformat:0|add:0 %}
|
||||||
|
<span class="text-yellow-500 text-base">★</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-gray-300 text-base">★</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<span class="text-gray-600 text-sm">({{ quiz.rating_count }})</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-gray-600 text-sm">Noch keine Bewertungen</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Authors -->
|
||||||
|
{% if quiz.authors.all %}
|
||||||
|
<div class="flex items-center gap-2 text-sm mt-2">
|
||||||
|
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-600">
|
||||||
|
{% for author in quiz.authors.all %}
|
||||||
|
{{ author.username }}{% if not forloop.last %}, {% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="flex justify-between items-center gap-2 mt-3 border-t pt-3">
|
||||||
|
{% if quiz.questions.count != 0 %}
|
||||||
|
<a href="{% url 'play:create_game' quiz.id %}"
|
||||||
|
class="px-3 py-1.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors duration-200 flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
Spielen
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
Fürs Spielen ist min. 1 Frage nötig!
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="flex gap-1">
|
||||||
|
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% if quiz.user_id == request.user %}
|
||||||
|
<a href="{% url 'library:edit_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'library:delete_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors duration-200">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination für Meine Quizze -->
|
||||||
|
{% if favorite_quizzes.paginator.num_pages > 1 %}
|
||||||
|
<div class="flex justify-center space-x-2 mt-6 mb-8">
|
||||||
|
{% if favorite_quizzes.has_previous %}
|
||||||
|
<a href="?my_page={{ favorite.previous_page_number }}{% if request.GET.all_page %}&all_page={{ request.GET.all_page }}{% endif %}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}"
|
||||||
|
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<span class="px-3 py-1 text-gray-600">Seite {{ favorite_quizzes.number }} von {{ favorite_quizzes.paginator.num_pages }}</span>
|
||||||
|
|
||||||
|
{% if favorite_quizzes.has_next %}
|
||||||
|
<a href="?favorite_page={{ favorite_quizzes.next_page_number }}{% if request.GET.all_page %}&all_page={{ request.GET.all_page }}{% endif %}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}"
|
||||||
|
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Alle -->
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-8 mb-6">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<h2 id="all-quizzes" class="text-2xl font-bold text-gray-900">Alle</h2>
|
||||||
|
<div class="h-0.5 flex-grow bg-gradient-to-r from-blue-600 to-transparent rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if all_quizzes %}
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 auto-rows-fr">
|
||||||
|
{% for quiz in all_quizzes %}
|
||||||
|
<article class="relative min-h-[20rem] rounded-xl shadow-lg overflow-hidden bg-white flex flex-col">
|
||||||
|
<!-- Image Section (Top) -->
|
||||||
|
<div class="h-48 w-full relative flex-shrink-0">
|
||||||
|
{% if quiz.image %}
|
||||||
|
<div class="relative w-full h-full inset-0 bg-cover bg-center">
|
||||||
|
<!-- Hintergrundbild -->
|
||||||
|
<div class="absolute inset-0 bg-cover bg-center"
|
||||||
|
style="background-image: url({{ quiz.image.image.url }});">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class="h-full bg-gradient-to-r from-blue-500 to-blue-600 flex items-center justify-center font-black text-white text-4xl px-4 overflow-auto break-words hyphens-auto ">{{ quiz.name }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
{% if quiz.id not in favorite_quiz_ids %}
|
||||||
|
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg">
|
||||||
|
|
||||||
|
<a href="{% url 'library:favorite_quiz' quiz.pk %}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-black size-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg">
|
||||||
|
<a href="{% url 'library:favorite_quiz' quiz.pk %}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-yellow-400 size-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Content Section (Bottom) -->
|
||||||
|
<div class="flex-grow bg-white p-4 flex flex-col gap-3">
|
||||||
|
<!-- Title -->
|
||||||
|
<h2 class="text-xl font-bold text-gray-900 break-words mb-2">
|
||||||
|
<a href="{% url 'library:detail_quiz' quiz.id %}" class="hover:text-blue-600 transition-colors">{{ quiz.name }}</a>
|
||||||
|
</h2>
|
||||||
|
<!-- Description -->
|
||||||
|
<p class="text-sm text-gray-700 break-words mb-3">{{ quiz.description }}</p>
|
||||||
|
|
||||||
|
<!-- Quiz Info Grid -->
|
||||||
|
<div class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
|
||||||
|
<!-- Difficulty -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800">{{ quiz.difficulty }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Questions Count -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800">{{ quiz.questions.count }} Fragen</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800">{{ quiz.status }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Rating -->
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
{% if quiz.rating_count > 0 %}
|
||||||
|
{% for i in '12345'|make_list %}
|
||||||
|
{% if forloop.counter <= quiz.average_rating|floatformat:0|add:0 %}
|
||||||
|
<span class="text-yellow-500 text-base">★</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-gray-300 text-base">★</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<span class="text-gray-600 text-sm">({{ quiz.rating_count }})</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-gray-600 text-sm">Noch keine Bewertungen</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Authors -->
|
||||||
|
{% if quiz.authors.all %}
|
||||||
|
<div class="flex items-center gap-2 text-sm mt-2">
|
||||||
|
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-600">
|
||||||
|
{% for author in quiz.authors.all %}
|
||||||
|
{{ author.username }}{% if not forloop.last %}, {% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="flex justify-between items-center gap-2 mt-3 border-t pt-3">
|
||||||
|
{% if quiz.questions.count != 0 %}
|
||||||
|
<a href="{% url 'play:create_game' quiz.id %}"
|
||||||
|
class="px-3 py-1.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors duration-200 flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
Spielen
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
Fürs Spielen ist min. 1 Frage nötig!
|
||||||
|
{% endif %}
|
||||||
|
<div class="flex gap-1">
|
||||||
|
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination für andere Quiz -->
|
||||||
|
{% if all_quizzes.paginator.num_pages > 1 %}
|
||||||
|
<div class="flex justify-center space-x-2 mt-6 mb-8">
|
||||||
|
{% if all_quizzes.has_previous %}
|
||||||
|
<a href="?all_page={{ all_quizzes.previous_page_number }}{% if request.GET.my_page %}&my_page={{ request.GET.my_page }}{% endif %}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}"
|
||||||
|
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<span class="px-3 py-1 text-gray-600">Seite {{ all_quizzes.number }} von {{ all_quizzes.paginator.num_pages }}</span>
|
||||||
|
|
||||||
|
{% if all_quizzes.has_next %}
|
||||||
|
<a href="?all_page={{ all_quizzes.next_page_number }}{% if request.GET.my_page %}&my_page={{ request.GET.my_page }}{% endif %}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}"
|
||||||
|
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-4">
|
||||||
|
<p class="text-gray-600 text-center">Keine öffentlichen Quiz gefunden.</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
if (urlParams.get('filter') === '1') {
|
||||||
|
document.getElementById('filterPanel').classList.add('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('filterButton').addEventListener('click', function() {
|
||||||
|
document.getElementById('filterPanel').classList.toggle('show');
|
||||||
|
|
||||||
|
// URL beim Öffnen aktualisieren
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
if (document.getElementById('filterPanel').classList.contains('show')) {
|
||||||
|
params.set('filter', '1');
|
||||||
|
} else {
|
||||||
|
params.delete('filter');
|
||||||
|
}
|
||||||
|
history.replaceState(null, '', `${location.pathname}?${params}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (window.location.pathname.includes("/library/")) {
|
||||||
|
window.addEventListener("beforeunload", function () {
|
||||||
|
localStorage.setItem("scroll-position", window.scrollY);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
const scrollPos = localStorage.getItem("scroll-position");
|
||||||
|
if (scrollPos !== null) {
|
||||||
|
window.scrollTo(0, parseInt(scrollPos));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{% endblock content %}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
{% load humanize %}
|
||||||
{% block extra_css %}
|
{% block extra_css %}
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
@@ -13,71 +13,54 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="container mx-auto px-4 py-4 flex justify-between items-center">
|
{% block head %}
|
||||||
<button id="filterButton" class="p-2 hover:bg-gray-100 rounded-lg transition-colors duration-200 flex items-center gap-2 text-gray-700">
|
{% include 'library/head.html' %}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
{% endblock %}
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
|
|
||||||
</svg>
|
|
||||||
<span>Filter</span>
|
|
||||||
</button>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<a href="{% url 'library:overview_quiz' %}" class="inline-flex items-center px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors duration-200">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
|
||||||
</svg>
|
|
||||||
Zurücksetzen
|
|
||||||
</a>
|
|
||||||
<a href="{% url 'library:new_quiz' %}" class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors duration-200">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
|
||||||
</svg>
|
|
||||||
Neues Quiz
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="filterPanel" class="container mx-auto px-4">
|
<!-- Alle -->
|
||||||
<div class="bg-white rounded-xl shadow-lg p-6 border border-gray-200">
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-8 mb-6 dark:text-white">
|
||||||
<form action="{% url 'library:overview_quiz' %}" method="get" class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
||||||
<input type="hidden" name="filter" value="1">
|
|
||||||
<div class="space-y-2">
|
|
||||||
<label class="block text-sm font-medium text-gray-700">minimale Anzahl an Fragen</label>
|
|
||||||
<input type="number" name="min_amout_questions" class="border-2 border-gray-300 rounded-lg p-2 w-full" min="1" id="id_min_amout_questions" value="{{ form.min_amout_questions.value|default_if_none:'' }}">
|
|
||||||
</div>
|
|
||||||
<div class="space-y-2">
|
|
||||||
<label class="block text-sm font-medium text-gray-700">maximale Anzahl an Fragen</label>
|
|
||||||
<input type="number" name="max_amout_questions" class="border-2 border-gray-300 rounded-lg p-2 w-full" min="1" id="id_max_amout_questions" value="{{ form.max_amout_questions.value|default_if_none:'' }}">
|
|
||||||
</div>
|
|
||||||
<div class="space-y-2">
|
|
||||||
<label class="block text-sm font-medium text-gray-700">veröffentlicht von User</label>
|
|
||||||
<input type="text" name="user" class="border-2 border-gray-300 rounded-lg p-2 w-full" id="id_user" value="{{ form.user.value|default_if_none:'' }}">
|
|
||||||
</div>
|
|
||||||
<div class="md:col-span-3 flex justify-end">
|
|
||||||
<button type="submit" class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors duration-200">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"></path>
|
|
||||||
</svg>
|
|
||||||
Filtern
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex justify-end text-sm mb-2">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6 text-blue-600">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
|
||||||
|
</svg>
|
||||||
|
<div class="gap-2 mx-2">
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
Anzahl aller Ergebnisse:
|
||||||
|
<span class="font-bold"> {{ total_all_found }}</span>
|
||||||
|
</div>
|
||||||
|
(verschiedene:
|
||||||
|
<span class="font-bold ml-1"> {{ total_all }}</span>)
|
||||||
|
{% else %}
|
||||||
|
Anzahl aller Ergebnisse:
|
||||||
|
<span class="font-bold"> {{ total_all_found }}</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-8 mb-6">
|
<div class="flex flex-wrap justify-end gap-4 font-bold text-blue-600 whitespace-nowrap text-sm mb-2 md:mb-0">
|
||||||
<div class="flex items-center gap-3">
|
<p class="font-black underline">Alle ({{ total_all }})</p>
|
||||||
<h2 id="my-quizzes" class="text-2xl font-bold text-gray-900">Eigene Quiz</h2>
|
<a href="{{ url_my }}?{{ request.GET.urlencode }}">Meine Quizze ({{ total_my }})</a>
|
||||||
<div class="h-0.5 flex-grow bg-gradient-to-r from-blue-600 to-transparent rounded-full"></div>
|
<a href="{{ url_favorite }}?{{ request.GET.urlencode }}">Meine Favoriten ({{ total_favorite }})</a>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<h2 id="all-quizzes" class="text-2xl font-bold text-gray-900 dark:text-white">Alle</h2>
|
||||||
|
<div class="h-0.5 flex-grow bg-gradient-to-r from-blue-600 to-transparent rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% if all_quizzes %}
|
||||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 auto-rows-fr">
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 auto-rows-fr">
|
||||||
{% for quiz in my_quizzes %}
|
{% for quiz in all_quizzes %}
|
||||||
<article class="relative min-h-[20rem] rounded-xl shadow-lg overflow-hidden bg-white flex flex-col">
|
<article class="relative min-h-[20rem] rounded-xl shadow-lg overflow-hidden flex flex-col">
|
||||||
<!-- Image Section (Top) -->
|
<!-- Image Section (Top) -->
|
||||||
<div class="h-48 w-full relative flex-shrink-0">
|
<div class="h-48 w-full relative flex-shrink-0">
|
||||||
{% if quiz.image %}
|
{% if quiz.image %}
|
||||||
@@ -89,23 +72,24 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="h-full bg-gradient-to-r from-blue-500 to-blue-600"></div>
|
<div class="h-full bg-gradient-to-r from-blue-500 to-blue-600 flex items-center justify-center font-black text-white text-3xl px-4 overflow-auto break-words hyphens-auto ">{{ quiz.name }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
{% if quiz.id not in favorite_quiz_ids %}
|
{% if quiz.id not in favorite_quiz_ids %}
|
||||||
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg">
|
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg dark:bg-[#2a2f3a]">
|
||||||
|
|
||||||
<a href="{% url 'library:favorite_quiz' quiz.pk %}">
|
<a class="favorite-link" href="{% url 'library:favorite_quiz' quiz.pk %}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-black size-6">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-black size-6 dark:text-white">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg">
|
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg dark:bg-[#2a2f3a]">
|
||||||
<a href="{% url 'library:favorite_quiz' quiz.pk %}">
|
<a class="favorite-link" href="{% url 'library:favorite_quiz' quiz.pk %}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-yellow-400 size-6">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-yellow-400 size-6">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
</svg>
|
</svg>
|
||||||
@@ -113,18 +97,27 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<div class="dark:bg-[#2a2f3a] max-w-6/10 h-max-12 truncate absolute top-4 left-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg ">
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="rounded-full w-4 h-4 flex-shrink-0" style="background-color: {{ quiz.category.color }};"></span>
|
||||||
|
<a class=" text-gray-800 truncate text-sm dark:text-white" title="{{ quiz.category }}" href="{% url 'library:overview_quiz' %}?filter=1&categories={{ quiz.category.id }}">{{ quiz.category }}</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Content Section (Bottom) -->
|
<!-- Content Section (Bottom) -->
|
||||||
<div class="flex-grow bg-white p-4 flex flex-col gap-3">
|
<div class="flex-grow bg-white p-4 flex flex-col gap-3 dark:bg-[#2a2f3a] dark:text-white" >
|
||||||
<!-- Title -->
|
<!-- Title -->
|
||||||
<h2 class="text-xl font-bold text-gray-900 break-words mb-2">
|
<h2 class="text-xl font-bold text-gray-900 break-words mb-2">
|
||||||
<a href="{% url 'library:detail_quiz' quiz.id %}" class="hover:text-blue-600 transition-colors">{{ quiz.name }}</a>
|
<a href="{% url 'library:detail_quiz' quiz.id %}" class="hover:text-blue-600 transition-colors dark:text-white">{{ quiz.name }}</a>
|
||||||
</h2>
|
</h2>
|
||||||
<!-- Description -->
|
<!-- Description -->
|
||||||
<p class="text-sm text-gray-700 break-words mb-3">{{ quiz.description }}</p>
|
<p class="text-sm text-gray-700 break-words mb-3 dark:text-white">{{ quiz.description }}</p>
|
||||||
|
|
||||||
<!-- Quiz Info Grid -->
|
<!-- Quiz Info Grid -->
|
||||||
<div class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
|
<div class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
|
||||||
@@ -133,7 +126,7 @@
|
|||||||
<svg class="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span class="text-gray-800">{{ quiz.difficulty }}</span>
|
<span class="text-gray-800 dark:text-white">{{ quiz.difficulty }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Questions Count -->
|
<!-- Questions Count -->
|
||||||
@@ -141,7 +134,7 @@
|
|||||||
<svg class="w-4 h-4 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-4 h-4 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span class="text-gray-800">{{ quiz.questions.count }} Fragen</span>
|
<span class="text-gray-800 dark:text-white">{{ quiz.questions.count }} Fragen</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Status -->
|
<!-- Status -->
|
||||||
@@ -149,9 +142,14 @@
|
|||||||
<svg class="w-4 h-4 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-4 h-4 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span class="text-gray-800">{{ quiz.status }}</span>
|
<span class="text-gray-800 dark:text-white">{{ quiz.status }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Rating -->
|
<!-- Rating -->
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
{% if quiz.rating_count > 0 %}
|
{% if quiz.rating_count > 0 %}
|
||||||
@@ -162,26 +160,37 @@
|
|||||||
<span class="text-gray-300 text-base">★</span>
|
<span class="text-gray-300 text-base">★</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<span class="text-gray-600 text-sm">({{ quiz.rating_count }})</span>
|
<span class="text-gray-600 text-sm dark:text-white">({{ quiz.rating_count }})</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="text-gray-600 text-sm">Noch keine Bewertungen</span>
|
<span class="text-gray-600 text-sm dark:text-white">Noch keine Bewertungen</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!--
|
||||||
<!-- Authors -->
|
{% if quiz.user_id %}
|
||||||
{% if quiz.authors.all %}
|
|
||||||
<div class="flex items-center gap-2 text-sm mt-2">
|
<div class="flex items-center gap-2 text-sm mt-2">
|
||||||
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span class="text-gray-600">
|
<span class="text-gray-600">
|
||||||
{% for author in quiz.authors.all %}
|
{{ quiz.user_id.username }}
|
||||||
{{ author.username }}{% if not forloop.last %}, {% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Zeit-->
|
||||||
|
{% if quiz.published_at != None %}
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2 ">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="text-green-400 size-4">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800 text-sm dark:text-white"><span class="font-medium dark:text-white">{{ quiz.published_at |naturaltime }}</span> <span class="text-sm">erst. veröffentlicht</span> </span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<div class="flex justify-between items-center gap-2 mt-3 border-t pt-3" >
|
<div class="flex justify-between items-center gap-2 mt-3 border-t pt-3" >
|
||||||
@@ -199,7 +208,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="flex gap-1">
|
<div class="flex gap-1">
|
||||||
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
||||||
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200">
|
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200 dark:bg-transparent dark:text-white dark:hover:bg-gray-700 ">
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
@@ -207,13 +216,13 @@
|
|||||||
</a>
|
</a>
|
||||||
{% if quiz.user_id == request.user %}
|
{% if quiz.user_id == request.user %}
|
||||||
<a href="{% url 'library:edit_quiz' quiz.id %}"
|
<a href="{% url 'library:edit_quiz' quiz.id %}"
|
||||||
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200">
|
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200 dark:bg-transparent dark:text-white dark:hover:bg-gray-700">
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
<a href="{% url 'library:delete_quiz' quiz.id %}"
|
<a href="{% url 'library:delete_quiz' quiz.id %}"
|
||||||
class="p-1.5 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors duration-200">
|
class="p-1.5 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors duration-200 dark:bg-transparent dark:text-white dark:hover:bg-gray-700">
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||||
</svg>
|
</svg>
|
||||||
@@ -224,388 +233,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Pagination für eigene Quiz -->
|
|
||||||
{% if my_quizzes.paginator.num_pages > 1 %}
|
|
||||||
<div class="flex justify-center space-x-2 mt-6 mb-8">
|
|
||||||
{% if my_quizzes.has_previous %}
|
|
||||||
<a href="?my_page={{ my_quizzes.previous_page_number }}{% if request.GET.other_page %}&other_page={{ request.GET.other_page }}{% endif %}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}"
|
|
||||||
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<span class="px-3 py-1 text-gray-600">Seite {{ my_quizzes.number }} von {{ my_quizzes.paginator.num_pages }}</span>
|
|
||||||
|
|
||||||
{% if my_quizzes.has_next %}
|
|
||||||
<a href="?my_page={{ my_quizzes.next_page_number }}{% if request.GET.other_page %}&other_page={{ request.GET.other_page }}{% endif %}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}"
|
|
||||||
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
|
||||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-8 mb-6">
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<h2 id="my-quizzes" class="text-2xl font-bold text-gray-900">Meine Favoriten</h2>
|
|
||||||
<div class="h-0.5 flex-grow bg-gradient-to-r from-blue-600 to-transparent rounded-full"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
|
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 auto-rows-fr">
|
|
||||||
{% for quiz in favorite_quizzes %}
|
|
||||||
<article class="relative min-h-[20rem] rounded-xl shadow-lg overflow-hidden bg-white flex flex-col">
|
|
||||||
<!-- Image Section (Top) -->
|
|
||||||
<div class="h-48 w-full relative flex-shrink-0">
|
|
||||||
{% if quiz.image %}
|
|
||||||
<div class="relative w-full h-full inset-0 bg-cover bg-center">
|
|
||||||
<!-- Hintergrundbild -->
|
|
||||||
<div class="absolute inset-0 bg-cover bg-center"
|
|
||||||
style="background-image: url({{ quiz.image.image.url }});">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
<div class="h-full bg-gradient-to-r from-blue-500 to-blue-600"></div>
|
|
||||||
{% endif %}
|
|
||||||
{% if user.is_authenticated %}
|
|
||||||
{% if quiz.favorite == False %}
|
|
||||||
|
|
||||||
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg">
|
|
||||||
|
|
||||||
<a href="{% url 'library:favorite_quiz' quiz.pk %}">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-black size-6">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg">
|
|
||||||
<a href="{% url 'library:favorite_quiz' quiz.pk %}">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-yellow-400 size-6">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Content Section (Bottom) -->
|
|
||||||
<div class="flex-grow bg-white p-4 flex flex-col gap-3">
|
|
||||||
<!-- Title -->
|
|
||||||
<h2 class="text-xl font-bold text-gray-900 break-words mb-2">
|
|
||||||
<a href="{% url 'library:detail_quiz' quiz.id %}" class="hover:text-blue-600 transition-colors">{{ quiz.name }}</a>
|
|
||||||
</h2>
|
|
||||||
<!-- Description -->
|
|
||||||
<p class="text-sm text-gray-700 break-words mb-3">{{ quiz.description }}</p>
|
|
||||||
|
|
||||||
<!-- Quiz Info Grid -->
|
|
||||||
<div class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
|
|
||||||
<!-- Difficulty -->
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<svg class="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
|
||||||
</svg>
|
|
||||||
<span class="text-gray-800">{{ quiz.difficulty }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Questions Count -->
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<svg class="w-4 h-4 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
<span class="text-gray-800">{{ quiz.questions.count }} Fragen</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Status -->
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<svg class="w-4 h-4 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
<span class="text-gray-800">{{ quiz.status }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Rating -->
|
|
||||||
<div class="flex items-center gap-1">
|
|
||||||
{% if quiz.rating_count > 0 %}
|
|
||||||
{% for i in '12345'|make_list %}
|
|
||||||
{% if forloop.counter <= quiz.average_rating|floatformat:0|add:0 %}
|
|
||||||
<span class="text-yellow-500 text-base">★</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="text-gray-300 text-base">★</span>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
<span class="text-gray-600 text-sm">({{ quiz.rating_count }})</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="text-gray-600 text-sm">Noch keine Bewertungen</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Authors -->
|
|
||||||
{% if quiz.authors.all %}
|
|
||||||
<div class="flex items-center gap-2 text-sm mt-2">
|
|
||||||
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
|
||||||
</svg>
|
|
||||||
<span class="text-gray-600">
|
|
||||||
{% for author in quiz.authors.all %}
|
|
||||||
{{ author.username }}{% if not forloop.last %}, {% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
|
||||||
<div class="flex justify-between items-center gap-2 mt-3 border-t pt-3">
|
|
||||||
{% if quiz.questions.count != 0 %}
|
|
||||||
<a href="{% url 'play:create_game' quiz.id %}"
|
|
||||||
class="px-3 py-1.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors duration-200 flex items-center gap-2">
|
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
Spielen
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
Fürs Spielen ist min. 1 Frage nötig!
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="flex gap-1">
|
|
||||||
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
|
||||||
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200">
|
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{% if quiz.user_id == request.user %}
|
|
||||||
<a href="{% url 'library:edit_quiz' quiz.id %}"
|
|
||||||
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200">
|
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
<a href="{% url 'library:delete_quiz' quiz.id %}"
|
|
||||||
class="p-1.5 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors duration-200">
|
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Pagination für eigene Quiz -->
|
|
||||||
{% if favorite_quizzes.paginator.num_pages > 1 %}
|
|
||||||
<div class="flex justify-center space-x-2 mt-6 mb-8">
|
|
||||||
{% if favorite_quizzes.has_previous %}
|
|
||||||
<a href="?my_page={{ my_quizzes.previous_page_number }}{% if request.GET.other_page %}&other_page={{ request.GET.other_page }}{% endif %}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}"
|
|
||||||
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<span class="px-3 py-1 text-gray-600">Seite {{ favorite_quizzes.number }} von {{ favorite_quizzes.paginator.num_pages }}</span>
|
|
||||||
|
|
||||||
{% if my_quizzes.has_next %}
|
|
||||||
<a href="?my_page={{ my_quizzes.next_page_number }}{% if request.GET.other_page %}&other_page={{ request.GET.other_page }}{% endif %}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}"
|
|
||||||
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Quiz von anderen Nutzern -->
|
|
||||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-8 mb-6">
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<h2 id="other-quizzes" class="text-2xl font-bold text-gray-900">Quiz von anderen Nutzern</h2>
|
|
||||||
<div class="h-0.5 flex-grow bg-gradient-to-r from-blue-600 to-transparent rounded-full"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if other_quizzes %}
|
|
||||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
|
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 auto-rows-fr">
|
|
||||||
{% for quiz in other_quizzes %}
|
|
||||||
<article class="relative min-h-[20rem] rounded-xl shadow-lg overflow-hidden bg-white flex flex-col">
|
|
||||||
<!-- Image Section (Top) -->
|
|
||||||
<div class="h-48 w-full relative flex-shrink-0">
|
|
||||||
{% if quiz.image %}
|
|
||||||
<div class="relative w-full h-full inset-0 bg-cover bg-center">
|
|
||||||
<!-- Hintergrundbild -->
|
|
||||||
<div class="absolute inset-0 bg-cover bg-center"
|
|
||||||
style="background-image: url({{ quiz.image.image.url }});">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
<div class="h-full bg-gradient-to-r from-blue-500 to-blue-600"></div>
|
|
||||||
{% endif %}
|
|
||||||
{% if user.is_authenticated %}
|
|
||||||
{% if quiz.id not in favorite_quiz_ids %}
|
|
||||||
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg">
|
|
||||||
|
|
||||||
<a href="{% url 'library:favorite_quiz' quiz.pk %}">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-black size-6">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg">
|
|
||||||
<a href="{% url 'library:favorite_quiz' quiz.pk %}">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-yellow-400 size-6">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Content Section (Bottom) -->
|
|
||||||
<div class="flex-grow bg-white p-4 flex flex-col gap-3">
|
|
||||||
<!-- Title -->
|
|
||||||
<h2 class="text-xl font-bold text-gray-900 break-words mb-2">
|
|
||||||
<a href="{% url 'library:detail_quiz' quiz.id %}" class="hover:text-blue-600 transition-colors">{{ quiz.name }}</a>
|
|
||||||
</h2>
|
|
||||||
<!-- Description -->
|
|
||||||
<p class="text-sm text-gray-700 break-words mb-3">{{ quiz.description }}</p>
|
|
||||||
|
|
||||||
<!-- Quiz Info Grid -->
|
|
||||||
<div class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
|
|
||||||
<!-- Difficulty -->
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<svg class="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
|
||||||
</svg>
|
|
||||||
<span class="text-gray-800">{{ quiz.difficulty }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Questions Count -->
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<svg class="w-4 h-4 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
<span class="text-gray-800">{{ quiz.questions.count }} Fragen</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Status -->
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<svg class="w-4 h-4 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
<span class="text-gray-800">{{ quiz.status }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Rating -->
|
|
||||||
<div class="flex items-center gap-1">
|
|
||||||
{% if quiz.rating_count > 0 %}
|
|
||||||
{% for i in '12345'|make_list %}
|
|
||||||
{% if forloop.counter <= quiz.average_rating|floatformat:0|add:0 %}
|
|
||||||
<span class="text-yellow-500 text-base">★</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="text-gray-300 text-base">★</span>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
<span class="text-gray-600 text-sm">({{ quiz.rating_count }})</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="text-gray-600 text-sm">Noch keine Bewertungen</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Authors -->
|
|
||||||
{% if quiz.authors.all %}
|
|
||||||
<div class="flex items-center gap-2 text-sm mt-2">
|
|
||||||
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
|
||||||
</svg>
|
|
||||||
<span class="text-gray-600">
|
|
||||||
{% for author in quiz.authors.all %}
|
|
||||||
{{ author.username }}{% if not forloop.last %}, {% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
|
||||||
<div class="flex justify-between items-center gap-2 mt-3 border-t pt-3">
|
|
||||||
{% if quiz.questions.count != 0 %}
|
|
||||||
<a href="{% url 'play:create_game' quiz.id %}"
|
|
||||||
class="px-3 py-1.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors duration-200 flex items-center gap-2">
|
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
Spielen
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
Fürs Spielen ist min. 1 Frage nötig!
|
|
||||||
{% endif %}
|
|
||||||
<div class="flex gap-1">
|
|
||||||
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
|
||||||
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200">
|
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pagination für andere Quiz -->
|
<!-- Pagination für andere Quiz -->
|
||||||
{% if other_quizzes.paginator.num_pages > 1 %}
|
{% if all_quizzes.paginator.num_pages > 1 %}
|
||||||
<div class="flex justify-center space-x-2 mt-6 mb-8">
|
<div class="flex justify-center space-x-2 mt-6 mb-8">
|
||||||
{% if other_quizzes.has_previous %}
|
{% if all_quizzes.has_previous %}
|
||||||
<a href="?other_page={{ other_quizzes.previous_page_number }}{% if request.GET.my_page %}&my_page={{ request.GET.my_page }}{% endif %}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}"
|
<a href="?all_page={{ all_quizzes.previous_page_number }}&{{ querystring_all }}"
|
||||||
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||||
@@ -613,10 +247,10 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<span class="px-3 py-1 text-gray-600">Seite {{ other_quizzes.number }} von {{ other_quizzes.paginator.num_pages }}</span>
|
<span class="px-3 py-1 text-gray-600 dark:text-white">Seite {{ all_quizzes.number }} von {{ all_quizzes.paginator.num_pages }}</span>
|
||||||
|
|
||||||
{% if other_quizzes.has_next %}
|
{% if all_quizzes.has_next %}
|
||||||
<a href="?other_page={{ other_quizzes.next_page_number }}{% if request.GET.my_page %}&my_page={{ request.GET.my_page }}{% endif %}{% if request.GET.search %}&search={{ request.GET.search }}{% endif %}"
|
<a href="?all_page={{ all_quizzes.next_page_number }}&{{ querystring_all }}"
|
||||||
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||||
@@ -628,44 +262,56 @@
|
|||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-4">
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-4">
|
||||||
<p class="text-gray-600 text-center">Keine öffentlichen Quiz gefunden.</p>
|
<p class="text-gray-600 text-center dark:text-white">Keine Quiz gefunden.</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}<script>
|
||||||
<script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const filterPanel = document.getElementById('filterPanel');
|
||||||
|
const filterButton = document.getElementById('filterButton');
|
||||||
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
if (urlParams.get('filter') === '1') {
|
if (urlParams.get('filter') === '1') {
|
||||||
document.getElementById('filterPanel').classList.add('show');
|
filterPanel.classList.add('show');
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('filterButton').addEventListener('click', function() {
|
filterButton.addEventListener('click', function () {
|
||||||
document.getElementById('filterPanel').classList.toggle('show');
|
filterPanel.classList.toggle('show');
|
||||||
|
|
||||||
// URL beim Öffnen aktualisieren
|
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
if (document.getElementById('filterPanel').classList.contains('show')) {
|
if (filterPanel.classList.contains('show')) {
|
||||||
params.set('filter', '1');
|
//params.set('filter', '1');
|
||||||
} else {
|
} else {
|
||||||
params.delete('filter');
|
params.delete('filter');
|
||||||
}
|
}
|
||||||
|
|
||||||
history.replaceState(null, '', `${location.pathname}?${params}`);
|
history.replaceState(null, '', `${location.pathname}?${params}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (window.location.pathname === "/library/") {
|
|
||||||
window.addEventListener("beforeunload", function () {
|
|
||||||
localStorage.setItem("meine_seite_scroll", window.scrollY);
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener("load", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
const scrollPos = localStorage.getItem("meine_seite_scroll");
|
// Scroll-Position beim Laden setzen
|
||||||
|
const scrollPos = localStorage.getItem("scroll-position");
|
||||||
if (scrollPos !== null) {
|
if (scrollPos !== null) {
|
||||||
window.scrollTo(0, parseInt(scrollPos));
|
window.scrollTo(0, parseInt(scrollPos));
|
||||||
}
|
localStorage.removeItem("scroll-position");
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nur Favoriten-Links abfangen
|
||||||
|
const favoriteLinks = document.querySelectorAll('a.favorite-link');
|
||||||
|
favoriteLinks.forEach(link => {
|
||||||
|
link.addEventListener('click', function () {
|
||||||
|
localStorage.setItem("scroll-position", window.scrollY);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
309
django/templates/library/overview_quiz_favorite.html
Normal file
309
django/templates/library/overview_quiz_favorite.html
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% load humanize %}
|
||||||
|
{% block extra_css %}
|
||||||
|
<style>
|
||||||
|
|
||||||
|
|
||||||
|
.custom-outline {
|
||||||
|
-webkit-text-stroke: 0.2px rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
{% include 'library/head.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-8 mb-6 dark:text-white">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex justify-end text-sm mb-2">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6 text-blue-600">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
|
||||||
|
</svg>
|
||||||
|
<div class="gap-2 mx-2 ">
|
||||||
|
Anzahl aller Ergebnisse:
|
||||||
|
<span class="font-bold"> {{ total_all_found }}</span>
|
||||||
|
</div>
|
||||||
|
(verschiedene:
|
||||||
|
<span class="font-bold ml-1"> {{ total_all }}</span>) </div>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap justify-end gap-4 font-bold text-blue-600 whitespace-nowrap text-sm mb-2 md:mb-0">
|
||||||
|
<a href="{{ url_all }}?{{ request.GET.urlencode }}">Alle ({{ total_all }})</a>
|
||||||
|
<a href="{{ url_my }}?{{ request.GET.urlencode }}">Meine Quizze ({{ total_my }})</a>
|
||||||
|
<p class="font-black underline">Meine Favoriten ({{ total_favorite }})</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<h2 id="my-quizzes" class="text-2xl font-bold text-gray-900 dark:text-white">Meine Favoriten</h2>
|
||||||
|
<div class="h-0.5 flex-grow bg-gradient-to-r from-blue-600 to-transparent rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if request.user.is_authenticated and favorite_quizzes %}
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 auto-rows-fr">
|
||||||
|
{% for quiz in favorite_quizzes %}
|
||||||
|
<article class="relative min-h-[20rem] rounded-xl shadow-lg overflow-hidden bg-white flex flex-col ">
|
||||||
|
<!-- Image Section (Top) -->
|
||||||
|
<div class="h-48 w-full relative flex-shrink-0 ">
|
||||||
|
{% if quiz.image %}
|
||||||
|
<div class="relative w-full h-full inset-0 bg-cover bg-center">
|
||||||
|
<!-- Hintergrundbild -->
|
||||||
|
<div class="absolute inset-0 bg-cover bg-center"
|
||||||
|
style="background-image: url({{ quiz.image.image.url }});">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class="h-full bg-gradient-to-r from-blue-500 to-blue-600 flex items-center justify-center font-black text-white text-3xl px-4 overflow-auto break-words hyphens-auto ">{{ quiz.name }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
{% if quiz.favorite == False %}
|
||||||
|
|
||||||
|
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg dark:bg-[#2a2f3a]">
|
||||||
|
|
||||||
|
<a class="favorite-link" href="{% url 'library:favorite_quiz' quiz.pk %}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-black size-6 dark:text-white">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg dark:bg-[#2a2f3a]">
|
||||||
|
<a class="favorite-link" href="{% url 'library:favorite_quiz' quiz.pk %}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-yellow-400 size-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
<div class="dark:bg-[#2a2f3a] max-w-6/10 h-max-12 truncate absolute top-4 left-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg ">
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="rounded-full w-4 h-4 flex-shrink-0" style="background-color: {{ quiz.category.color }};"></span>
|
||||||
|
|
||||||
|
<a class=" text-gray-800 truncate text-sm dark:text-white" title="{{ quiz.category }}" href="{% url 'library:overview_quiz' %}?filter=1&categories={{ quiz.category.id }}">{{ quiz.category }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Content Section (Bottom) -->
|
||||||
|
<div class="flex-grow bg-white p-4 flex flex-col gap-3 dark:bg-[#2a2f3a] dark:text-white">
|
||||||
|
<!-- Title -->
|
||||||
|
<h2 class="text-xl font-bold text-gray-900 break-words mb-2">
|
||||||
|
<a href="{% url 'library:detail_quiz' quiz.id %}" class="hover:text-blue-600 transition-colors dark:text-white">{{ quiz.name }}</a>
|
||||||
|
</h2>
|
||||||
|
<!-- Description -->
|
||||||
|
<p class="text-sm text-gray-700 break-words mb-3 dark:text-white">{{ quiz.description }}</p>
|
||||||
|
|
||||||
|
<!-- Quiz Info Grid -->
|
||||||
|
<div class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
|
||||||
|
<!-- Difficulty -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800 dark:text-white">{{ quiz.difficulty }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Questions Count -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800 dark:text-white">{{ quiz.questions.count }} Fragen</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800 dark:text-white">{{ quiz.status }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Rating -->
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
{% if quiz.rating_count > 0 %}
|
||||||
|
{% for i in '12345'|make_list %}
|
||||||
|
{% if forloop.counter <= quiz.average_rating|floatformat:0|add:0 %}
|
||||||
|
<span class="text-yellow-500 text-base">★</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-gray-300 text-base">★</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<span class="text-gray-600 text-sm dark:text-white">({{ quiz.rating_count }})</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-gray-600 text-sm dark:text-white">Noch keine Bewertungen</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Authors -->
|
||||||
|
<!--
|
||||||
|
{% if quiz.authors.all %}
|
||||||
|
<div class="flex items-center gap-2 text-sm mt-2">
|
||||||
|
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-600">
|
||||||
|
{% for author in quiz.authors.all %}
|
||||||
|
{{ author.username }}{% if not forloop.last %}, {% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}-->
|
||||||
|
|
||||||
|
<!-- Zeit-->
|
||||||
|
{% if quiz.published_at != None %}
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2 ">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="text-green-400 size-4">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800 text-sm dark:text-white "><span class="font-medium dark:text-white">{{ quiz.published_at |naturaltime }}</span> <span class="text-sm">erst. veröffentlicht</span> </span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="flex justify-between items-center gap-2 mt-3 border-t pt-3">
|
||||||
|
{% if quiz.questions.count != 0 %}
|
||||||
|
<a href="{% url 'play:create_game' quiz.id %}"
|
||||||
|
class="px-3 py-1.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors duration-200 flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
Spielen
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
Fürs Spielen ist min. 1 Frage nötig!
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="flex gap-1">
|
||||||
|
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200 dark:bg-transparent dark:text-white dark:hover:bg-gray-700">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% if quiz.user_id == request.user %}
|
||||||
|
<a href="{% url 'library:edit_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200 dark:bg-transparent dark:text-white dark:hover:bg-gray-700">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'library:delete_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors duration-200 dark:bg-transparent dark:text-white dark:hover:bg-gray-700">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination für favorite Quizze -->
|
||||||
|
{% if favorite_quizzes.paginator.num_pages > 1 %}
|
||||||
|
<div class="flex justify-center space-x-2 mt-6 mb-8 ">
|
||||||
|
{% if favorite_quizzes.has_previous %}
|
||||||
|
<a href="?favorite_page={{ favorite.previous_page_number }}&{{ querystring_favorite }}"
|
||||||
|
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<span class="dark:text-white px-3 py-1 text-gray-600">Seite {{ favorite_quizzes.number }} von {{ favorite_quizzes.paginator.num_pages }}</span>
|
||||||
|
|
||||||
|
{% if favorite_quizzes.has_next %}
|
||||||
|
<a href="?favorite_page={{ favorite_quizzes.next_page_number }}&{{ querystring_favorite }}"
|
||||||
|
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-4">
|
||||||
|
<p class="text-gray-600 text-center dark:text-white">Keine favorisierten Quiz gefunden.</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const filterPanel = document.getElementById('filterPanel');
|
||||||
|
const filterButton = document.getElementById('filterButton');
|
||||||
|
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
if (urlParams.get('filter') === '1') {
|
||||||
|
filterPanel.classList.add('show');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
filterButton.addEventListener('click', function () {
|
||||||
|
filterPanel.classList.toggle('show');
|
||||||
|
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
if (filterPanel.classList.contains('show')) {
|
||||||
|
//params.set('filter', '1');
|
||||||
|
} else {
|
||||||
|
params.delete('filter');
|
||||||
|
}
|
||||||
|
|
||||||
|
history.replaceState(null, '', `${location.pathname}?${params}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
// Scroll-Position beim Laden setzen
|
||||||
|
const scrollPos = localStorage.getItem("scroll-position");
|
||||||
|
if (scrollPos !== null) {
|
||||||
|
window.scrollTo(0, parseInt(scrollPos));
|
||||||
|
localStorage.removeItem("scroll-position");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nur Favoriten-Links abfangen
|
||||||
|
const favoriteLinks = document.querySelectorAll('a.favorite-link');
|
||||||
|
favoriteLinks.forEach(link => {
|
||||||
|
link.addEventListener('click', function () {
|
||||||
|
localStorage.setItem("scroll-position", window.scrollY);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% endblock content %}
|
||||||
306
django/templates/library/overview_quiz_my.html
Normal file
306
django/templates/library/overview_quiz_my.html
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% load humanize %}
|
||||||
|
{% block extra_css %}
|
||||||
|
<style>
|
||||||
|
|
||||||
|
|
||||||
|
.custom-outline {
|
||||||
|
-webkit-text-stroke: 0.2px rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
{% include 'library/head.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-8 mb-6 dark:text-white">
|
||||||
|
|
||||||
|
<div class="flex justify-end text-sm mb-2">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6 text-blue-600">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
|
||||||
|
</svg>
|
||||||
|
<div class="gap-2 mx-2">
|
||||||
|
Anzahl aller Ergebnisse:
|
||||||
|
<span class="font-bold"> {{ total_all_found }}</span>
|
||||||
|
</div>
|
||||||
|
(verschiedene:
|
||||||
|
<span class="font-bold ml-1"> {{ total_all }}</span>) </div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex flex-wrap justify-end gap-4 font-bold text-blue-600 whitespace-nowrap text-sm mb-2 md:mb-0">
|
||||||
|
<a href="{{ url_all }}?{{ request.GET.urlencode }}">Alle ({{ total_all }})</a>
|
||||||
|
<p class="font-black underline">Meine Quizze ({{ total_my }})</p>
|
||||||
|
<a href="{{ url_favorite }}?{{ request.GET.urlencode }}">Meine Favoriten ({{ total_favorite }})</a>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<h2 id="my-quizzes" class="text-2xl font-bold text-gray-900 dark:text-white">Meine Quizze</h2>
|
||||||
|
<div class="h-0.5 flex-grow bg-gradient-to-r from-blue-600 to-transparent rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if request.user.is_authenticated and my_quizzes %}
|
||||||
|
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 auto-rows-fr">
|
||||||
|
{% for quiz in my_quizzes %}
|
||||||
|
<article class="relative min-h-[20rem] rounded-xl shadow-lg overflow-hidden bg-white flex flex-col">
|
||||||
|
<!-- Image Section (Top) -->
|
||||||
|
<div class="h-48 w-full relative flex-shrink-0">
|
||||||
|
{% if quiz.image %}
|
||||||
|
<div class="relative w-full h-full inset-0 bg-cover bg-center">
|
||||||
|
<!-- Hintergrundbild -->
|
||||||
|
<div class="absolute inset-0 bg-cover bg-center"
|
||||||
|
style="background-image: url({{ quiz.image.image.url }});">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class="h-full bg-gradient-to-r from-blue-500 to-blue-600 flex items-center justify-center font-black text-white text-3xl px-4 overflow-auto break-words hyphens-auto ">{{ quiz.name }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
{% if quiz.id not in favorite_quiz_ids %}
|
||||||
|
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg dark:bg-[#2a2f3a]">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a class="favorite-link" href="{% url 'library:favorite_quiz' quiz.pk %}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-black size-6 dark:text-white">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class="absolute top-4 right-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg dark:bg-[#2a2f3a]">
|
||||||
|
<a class="favorite-link" href="{% url 'library:favorite_quiz' quiz.pk %}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="text-yellow-400 size-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
<div class="dark:bg-[#2a2f3a] max-w-6/10 h-max-12 truncate absolute top-4 left-4 bg-white bg-opacity-60 text-white px-4 py-2 rounded-lg shadow-lg ">
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="rounded-full w-4 h-4 flex-shrink-0" style="background-color: {{ quiz.category.color }};"></span>
|
||||||
|
<a class=" text-gray-800 truncate text-sm dark:text-white" title="{{ quiz.category }}" href="{% url 'library:overview_quiz' %}?filter=1&categories={{ quiz.category.id }}">{{ quiz.category }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Content Section (Bottom) -->
|
||||||
|
<div class="flex-grow bg-white p-4 flex flex-col gap-3 dark:bg-[#2a2f3a] dark:text-white">
|
||||||
|
<!-- Title -->
|
||||||
|
<h2 class="text-xl font-bold text-gray-900 break-words mb-2">
|
||||||
|
<a href="{% url 'library:detail_quiz' quiz.id %}" class="hover:text-blue-600 transition-colors dark:text-white">{{ quiz.name }}</a>
|
||||||
|
</h2>
|
||||||
|
<!-- Description -->
|
||||||
|
<p class="text-sm text-gray-700 break-words mb-3 dark:text-white">{{ quiz.description }}</p>
|
||||||
|
|
||||||
|
<!-- Quiz Info Grid -->
|
||||||
|
<div class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
|
||||||
|
<!-- Difficulty -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800 dark:text-white">{{ quiz.difficulty }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Questions Count -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800 dark:text-white">{{ quiz.questions.count }} Fragen</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status -->
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800 dark:text-white">{{ quiz.status }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Rating -->
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
{% if quiz.rating_count > 0 %}
|
||||||
|
{% for i in '12345'|make_list %}
|
||||||
|
{% if forloop.counter <= quiz.average_rating|floatformat:0|add:0 %}
|
||||||
|
<span class="text-yellow-500 text-base">★</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-gray-300 text-base">★</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<span class="text-gray-600 text-sm dark:text-white">({{ quiz.rating_count }})</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-gray-600 text-sm dark:text-white">Noch keine Bewertungen</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Authors -->
|
||||||
|
<!--
|
||||||
|
{% if quiz.authors.all %}
|
||||||
|
<div class="flex items-center gap-2 text-sm mt-2">
|
||||||
|
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-600">
|
||||||
|
{% for author in quiz.authors.all %}
|
||||||
|
{{ author.username }}{% if not forloop.last %}, {% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Zeit-->
|
||||||
|
{% if quiz.published_at != None %}
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2 ">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="text-green-400 size-4">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-gray-800 text-sm dark:text-white"><span class="font-medium dark:text-white">{{ quiz.published_at |naturaltime }}</span> <span class="text-sm">erst. veröffentlicht</span> </span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="flex justify-between items-center gap-2 mt-3 border-t pt-3">
|
||||||
|
{% if quiz.questions.count != 0 %}
|
||||||
|
<a href="{% url 'play:create_game' quiz.id %}"
|
||||||
|
class="px-3 py-1.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors duration-200 flex items-center gap-2">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
Spielen
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
Fürs Spielen ist min. 1 Frage nötig!
|
||||||
|
{% endif %}
|
||||||
|
<div class="flex gap-1">
|
||||||
|
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200 dark:bg-transparent dark:text-white dark:hover:bg-gray-700">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% if quiz.user_id == request.user %}
|
||||||
|
<a href="{% url 'library:edit_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors duration-200 dark:bg-transparent dark:text-white dark:hover:bg-gray-700">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'library:delete_quiz' quiz.id %}"
|
||||||
|
class="p-1.5 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors duration-200 dark:bg-transparent dark:text-white dark:hover:bg-gray-700">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination für Meine Quizze -->
|
||||||
|
{% if my_quizzes.paginator.num_pages > 1 %}
|
||||||
|
<div class="flex justify-center space-x-2 mt-6 mb-8">
|
||||||
|
{% if my_quizzes.has_previous %}
|
||||||
|
<a href="?my_page={{ my_quizzes.previous_page_number }}&{{ querystring_my }}"
|
||||||
|
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<span class="px-3 py-1 text-gray-600 dark:text-white">Seite {{ my_quizzes.number }} von {{ my_quizzes.paginator.num_pages }}</span>
|
||||||
|
|
||||||
|
{% if my_quizzes.has_next %}
|
||||||
|
<a href="?my_page={{ my_quizzes.next_page_number }}&{{ querystring_my }}"
|
||||||
|
class="px-3 py-1 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg transition-colors">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="container mx-auto px-4 sm:px-6 lg:px-8 mt-4">
|
||||||
|
<p class="text-gray-600 text-center dark:text-white">Keine eigenen Quiz gefunden.</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const filterPanel = document.getElementById('filterPanel');
|
||||||
|
const filterButton = document.getElementById('filterButton');
|
||||||
|
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
if (urlParams.get('filter') === '1') {
|
||||||
|
filterPanel.classList.add('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
filterButton.addEventListener('click', function () {
|
||||||
|
filterPanel.classList.toggle('show');
|
||||||
|
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
if (filterPanel.classList.contains('show')) {
|
||||||
|
//params.set('filter', '1');
|
||||||
|
} else {
|
||||||
|
params.delete('filter');
|
||||||
|
}
|
||||||
|
|
||||||
|
history.replaceState(null, '', `${location.pathname}?${params}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
// Scroll-Position beim Laden setzen
|
||||||
|
const scrollPos = localStorage.getItem("scroll-position");
|
||||||
|
if (scrollPos !== null) {
|
||||||
|
window.scrollTo(0, parseInt(scrollPos));
|
||||||
|
localStorage.removeItem("scroll-position");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nur Favoriten-Links abfangen
|
||||||
|
const favoriteLinks = document.querySelectorAll('a.favorite-link');
|
||||||
|
favoriteLinks.forEach(link => {
|
||||||
|
link.addEventListener('click', function () {
|
||||||
|
localStorage.setItem("scroll-position", window.scrollY);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock content %}
|
||||||
@@ -3,23 +3,23 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mx-auto px-4">
|
<div class="container mx-auto px-4">
|
||||||
<div class="flex justify-between items-center mb-6">
|
<div class="flex justify-between items-center mb-6">
|
||||||
<h1 class="text-2xl font-bold">{% if question %}Frage bearbeiten{% else %}Neue Eingabe Frage{% endif %}</h1>
|
<h1 class="text-2xl font-bold dark:text-white">{% if question %}Frage bearbeiten{% else %}Neue Eingabe Frage{% endif %}</h1>
|
||||||
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
||||||
class="bg-gray-100 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-200 transition-colors">
|
class="bg-gray-100 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-200 transition-colors">
|
||||||
Zurück zum Quiz
|
Zurück zum Quiz
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white rounded-lg shadow-md p-6 border-blue-600 border-2 rounded-xl shadow-md">
|
<div class="bg-white rounded-lg shadow-md p-6 border-blue-600 border-2 rounded-xl shadow-md dark:bg-transparent dark:text-white">
|
||||||
<form method="post" class="space-y-6" enctype="multipart/form-data">
|
<form method="post" class="space-y-6" enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<!-- Question Text -->
|
<!-- Question Text -->
|
||||||
<div>
|
<div>
|
||||||
<label for="question" class="block text-sm font-medium text-gray-700">Frage</label>
|
<label for="question" class="block text-sm font-medium text-gray-700 dark:text-white">Frage</label>
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
<textarea name="question" id="question" rows="4"
|
<textarea name="question" id="question" rows="4"
|
||||||
class="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
class="dark:bg-[#2a2f3a] shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
||||||
required>{{ question.data.question }}</textarea>
|
required>{{ question.data.question }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -33,17 +33,17 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<div>
|
<div>
|
||||||
<label class="font-bold" for="question_image">Bild:</label>
|
<label class="font-bold" for="question_image">Bild:</label>
|
||||||
<input class="bg-blue-200 p-2 m-2 rounded-lg border-2 border-blue-400" type="file" name="question_image" id="question_image">
|
<input class="max-w-full bg-blue-200 p-2 m-2 rounded-lg border-2 border-blue-400 dark:bg-transparent" type="file" name="question_image" id="question_image">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Eingabe -->
|
<!-- Eingabe -->
|
||||||
{% if question and question.data.options %}
|
{% if question and question.data.options %}
|
||||||
{% for option in question.data.options %}
|
{% for option in question.data.options %}
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Richtige Antwort</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2 dark:text-white">Richtige Antwort</label>
|
||||||
<div class="flex space-x-4">
|
<div class="flex space-x-4">
|
||||||
<textarea name="correct_answer" rows="2"
|
<textarea name="correct_answer" rows="2"
|
||||||
class="shadow-sm focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
class="dark:bg-[#2a2f3a] focus:outline-none focus:ring-2 shadow-sm focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
||||||
required>{{ option.value }}</textarea>
|
required>{{ option.value }}</textarea>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -52,10 +52,10 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Richtige Antwort</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2 dark:text-white">Richtige Antwort</label>
|
||||||
<div class="flex space-x-4">
|
<div class="flex space-x-4">
|
||||||
<textarea name="correct_answer" rows="2"
|
<textarea name="correct_answer" rows="2"
|
||||||
class="shadow-sm focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
class="dark:bg-[#2a2f3a] shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
||||||
required></textarea>
|
required></textarea>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
|
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<label class="font-bold" for="time_per_question">Zeit pro Frage:</label>
|
<label class="font-bold" for="time_per_question">Zeit pro Frage:</label>
|
||||||
<select name="time_per_question" id="time_per_question">
|
<select name="time_per_question" id="time_per_question" class="dark:text-white dark:bg-[#2a2f3a] focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||||
<option value="10" {% if standard_time_per_question == "10" or time_per_question == "10" %}selected{% endif %}>10 Sekunden</option>
|
<option value="10" {% if standard_time_per_question == "10" or time_per_question == "10" %}selected{% endif %}>10 Sekunden</option>
|
||||||
<option value="20" {% if standard_time_per_question == "20" or time_per_question == "20" %}selected{% endif %}>20 Sekunden</option>
|
<option value="20" {% if standard_time_per_question == "20" or time_per_question == "20" %}selected{% endif %}>20 Sekunden</option>
|
||||||
<option value="30" {% if standard_time_per_question == "30" or time_per_question == "30" %}selected{% endif %}>30 Sekunden</option>
|
<option value="30" {% if standard_time_per_question == "30" or time_per_question == "30" %}selected{% endif %}>30 Sekunden</option>
|
||||||
@@ -75,6 +75,12 @@
|
|||||||
<option value="120" {% if standard_time_per_question == "120" or time_per_question == "120" %}selected{% endif %}>2 Minuten</option>
|
<option value="120" {% if standard_time_per_question == "120" or time_per_question == "120" %}selected{% endif %}>2 Minuten</option>
|
||||||
<option value="300" {% if standard_time_per_question == "300" or time_per_question == "300" %}selected{% endif %}>5 Minuten</option>
|
<option value="300" {% if standard_time_per_question == "300" or time_per_question == "300" %}selected{% endif %}>5 Minuten</option>
|
||||||
</select>
|
</select>
|
||||||
|
</div>
|
||||||
|
<label for="credits" class="block text-sm font-medium text-gray-700 dark:text-white">Credits</label>
|
||||||
|
<div class="mt-1">
|
||||||
|
<textarea name="credits" rows="4"
|
||||||
|
class="dark:bg-[#2a2f3a] shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
||||||
|
>{{ credits }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end space-x-3">
|
<div class="flex justify-end space-x-3">
|
||||||
|
|||||||
@@ -3,22 +3,22 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mx-auto px-4">
|
<div class="container mx-auto px-4">
|
||||||
<div class="flex justify-between items-center mb-6">
|
<div class="flex justify-between items-center mb-6">
|
||||||
<h1 class="text-2xl font-bold">{% if question %}Frage bearbeiten{% else %}Neue Multiple Choice Frage{% endif %}</h1>
|
<h1 class="text-2xl font-bold dark:text-white">{% if question %}Frage bearbeiten{% else %}Neue Multiple Choice Frage{% endif %}</h1>
|
||||||
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
||||||
class="bg-gray-100 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-200 transition-colors">
|
class="bg-gray-100 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-200 transition-colors">
|
||||||
Zurück zum Quiz
|
Zurück zum Quiz
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white rounded-lg shadow-md p-6 border-blue-600 border-2 rounded-xl shadow-md">
|
<div class="bg-white rounded-lg shadow-md p-6 border-blue-600 border-2 rounded-xl shadow-md dark:bg-transparent dark:text-white">
|
||||||
<form method="post" class="space-y-6" enctype="multipart/form-data">
|
<form method="post" class="space-y-6" enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<!-- Question Text -->
|
<!-- Question Text -->
|
||||||
<div>
|
<div>
|
||||||
<label for="question" class="block text-sm font-medium text-gray-700">Frage</label>
|
<label for="question" class="block text-sm font-medium text-gray-700 dark:text-white">Frage</label>
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
<textarea name="question" id="question" rows="4"
|
<textarea name="question" id="question" rows="4"
|
||||||
class="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
class="dark:bg-[#2a2f3a] shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
||||||
required>{{ question.data.question|default:'' }}</textarea>
|
required>{{ question.data.question|default:'' }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -33,24 +33,24 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<div>
|
<div>
|
||||||
<label class="font-bold" for="question_image">Bild:</label>
|
<label class="font-bold" for="question_image">Bild:</label>
|
||||||
<input value="image.url" class="bg-blue-200 p-2 m-2 rounded-lg border-2 border-blue-400" type="file" name="question_image" id="question_image">
|
<input value="image.url" class="max-w-full bg-blue-200 p-2 m-2 rounded-lg border-2 border-blue-400 dark:bg-transparent" type="file" name="question_image" id="question_image">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Options -->
|
<!-- Options -->
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Antwortmöglichkeiten</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2 dark:text-white">Antwortmöglichkeiten</label>
|
||||||
<div id="options-container" class="space-y-3">
|
<div id="options-container" class="space-y-3">
|
||||||
{% if question and question.data.options %}
|
{% if question and question.data.options %}
|
||||||
{% for option in question.data.options %}
|
{% for option in question.data.options %}
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<textarea name="option_{{ forloop.counter }}" rows="2"
|
<textarea name="option_{{ forloop.counter }}" rows="2"
|
||||||
class="shadow-sm focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
class="dark:bg-[#2a2f3a] shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
||||||
required>{{ option.value }}</textarea>
|
required>{{ option.value }}</textarea>
|
||||||
<label class="inline-flex items-center">
|
<label class="inline-flex items-center">
|
||||||
<input type="checkbox" name="correct_{{ forloop.counter }}" value="1"
|
<input type="checkbox" name="correct_{{ forloop.counter }}" value="1"
|
||||||
class="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded"
|
class=" focus:outline-none focus:ring-2 focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded"
|
||||||
{% if option.is_correct %}checked{% endif %}>
|
{% if option.is_correct %}checked{% endif %}>
|
||||||
<span class="ml-2 text-sm text-gray-600">Richtig</span>
|
<span class="ml-2 text-sm text-gray-600 dark:text-white">Richtig</span>
|
||||||
</label>
|
</label>
|
||||||
<button type="button" onclick="removeOption(this)"
|
<button type="button" onclick="removeOption(this)"
|
||||||
class="text-red-600 hover:text-red-800 transition-colors">
|
class="text-red-600 hover:text-red-800 transition-colors">
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<textarea name="option_1" rows="2"
|
<textarea name="option_1" rows="2"
|
||||||
class="shadow-sm focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
class="shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
||||||
required></textarea>
|
required></textarea>
|
||||||
<label class="inline-flex items-center">
|
<label class="inline-flex items-center">
|
||||||
<input type="checkbox" name="correct_1" value="1"
|
<input type="checkbox" name="correct_1" value="1"
|
||||||
@@ -79,10 +79,42 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<textarea name="option_2" rows="2"
|
<textarea name="option_2" rows="2"
|
||||||
class="shadow-sm focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
class="shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
||||||
required></textarea>
|
required></textarea>
|
||||||
<label class="inline-flex items-center">
|
<label class="inline-flex items-center">
|
||||||
<input type="checkbox" name="correct_2" value="1"
|
<input type="checkbox" name="correct_2" value="1"
|
||||||
|
class=" focus:outline-none focus:ring-2 focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded">
|
||||||
|
<span class="ml-2 text-sm text-gray-600">Richtig</span>
|
||||||
|
</label>
|
||||||
|
<button type="button" onclick="removeOption(this)"
|
||||||
|
class="text-red-600 hover:text-red-800 transition-colors">
|
||||||
|
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-3">
|
||||||
|
<textarea name="option_3" rows="2"
|
||||||
|
class="shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
||||||
|
required></textarea>
|
||||||
|
<label class="inline-flex items-center">
|
||||||
|
<input type="checkbox" name="correct_3" value="1"
|
||||||
|
class="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded">
|
||||||
|
<span class="ml-2 text-sm text-gray-600">Richtig</span>
|
||||||
|
</label>
|
||||||
|
<button type="button" onclick="removeOption(this)"
|
||||||
|
class="text-red-600 hover:text-red-800 transition-colors">
|
||||||
|
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-3">
|
||||||
|
<textarea name="option_4" rows="2"
|
||||||
|
class="shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
||||||
|
required></textarea>
|
||||||
|
<label class="inline-flex items-center">
|
||||||
|
<input type="checkbox" name="correct_4" value="1"
|
||||||
class="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded">
|
class="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded">
|
||||||
<span class="ml-2 text-sm text-gray-600">Richtig</span>
|
<span class="ml-2 text-sm text-gray-600">Richtig</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -106,7 +138,7 @@
|
|||||||
|
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<label class="font-bold" for="time_per_question">Zeit pro Frage:</label>
|
<label class="font-bold" for="time_per_question">Zeit pro Frage:</label>
|
||||||
<select name="time_per_question" id="time_per_question">
|
<select name="time_per_question" id="time_per_question" class="dark:text-white dark:bg-[#2a2f3a] focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||||
<option value="10" {% if standard_time_per_question == "10" or time_per_question == "10" %}selected{% endif %}>10 Sekunden</option>
|
<option value="10" {% if standard_time_per_question == "10" or time_per_question == "10" %}selected{% endif %}>10 Sekunden</option>
|
||||||
<option value="20" {% if standard_time_per_question == "20" or time_per_question == "20" %}selected{% endif %}>20 Sekunden</option>
|
<option value="20" {% if standard_time_per_question == "20" or time_per_question == "20" %}selected{% endif %}>20 Sekunden</option>
|
||||||
<option value="30" {% if standard_time_per_question == "30" or time_per_question == "30" %}selected{% endif %}>30 Sekunden</option>
|
<option value="30" {% if standard_time_per_question == "30" or time_per_question == "30" %}selected{% endif %}>30 Sekunden</option>
|
||||||
@@ -115,6 +147,12 @@
|
|||||||
<option value="120" {% if standard_time_per_question == "120" or time_per_question == "120" %}selected{% endif %}>2 Minuten</option>
|
<option value="120" {% if standard_time_per_question == "120" or time_per_question == "120" %}selected{% endif %}>2 Minuten</option>
|
||||||
<option value="300" {% if standard_time_per_question == "300" or time_per_question == "300" %}selected{% endif %}>5 Minuten</option>
|
<option value="300" {% if standard_time_per_question == "300" or time_per_question == "300" %}selected{% endif %}>5 Minuten</option>
|
||||||
</select>
|
</select>
|
||||||
|
</div>
|
||||||
|
<label for="credits" class="block text-sm font-medium text-gray-700 dark:text-white">Credits</label>
|
||||||
|
<div class="mt-1">
|
||||||
|
<textarea name="credits" rows="4"
|
||||||
|
class="dark:bg-[#2a2f3a] shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md "
|
||||||
|
>{{ credits }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end space-x-3">
|
<div class="flex justify-end space-x-3">
|
||||||
@@ -144,13 +182,14 @@ function addOption() {
|
|||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.className = 'flex items-center space-x-3';
|
div.className = 'flex items-center space-x-3';
|
||||||
div.innerHTML = `
|
div.innerHTML = `
|
||||||
<textarea name="option_${optionCount}" rows="2"
|
<textarea name="option_{{ forloop.counter }}" rows="2"
|
||||||
class="shadow-sm focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
class="dark:bg-[#2a2f3a] shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 flex-grow sm:text-sm border-gray-300 rounded-md"
|
||||||
required></textarea>
|
required>{{ option.value }}</textarea>
|
||||||
<label class="inline-flex items-center">
|
<label class="inline-flex items-center">
|
||||||
<input type="checkbox" name="correct_${optionCount}" value="1"
|
<input type="checkbox" name="correct_{{ forloop.counter }}" value="1"
|
||||||
class="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded">
|
class=" focus:outline-none focus:ring-2 focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded"
|
||||||
<span class="ml-2 text-sm text-gray-600">Richtig</span>
|
{% if option.is_correct %}checked{% endif %}>
|
||||||
|
<span class="ml-2 text-sm text-gray-600 dark:text-white">Richtig</span>
|
||||||
</label>
|
</label>
|
||||||
<button type="button" onclick="removeOption(this)"
|
<button type="button" onclick="removeOption(this)"
|
||||||
class="text-red-600 hover:text-red-800 transition-colors">
|
class="text-red-600 hover:text-red-800 transition-colors">
|
||||||
|
|||||||
@@ -3,23 +3,23 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mx-auto px-4">
|
<div class="container mx-auto px-4">
|
||||||
<div class="flex justify-between items-center mb-6">
|
<div class="flex justify-between items-center mb-6">
|
||||||
<h1 class="text-2xl font-bold">{% if question %}Frage bearbeiten{% else %}Neue Wahr/Falsch Frage{% endif %}</h1>
|
<h1 class="text-2xl font-bold dark:text-white">{% if question %}Frage bearbeiten{% else %}Neue Wahr/Falsch Frage{% endif %}</h1>
|
||||||
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
||||||
class="bg-gray-100 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-200 transition-colors">
|
class="bg-gray-100 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-200 transition-colors">
|
||||||
Zurück zum Quiz
|
Zurück zum Quiz
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white rounded-lg shadow-md p-6 border-blue-600 border-2 rounded-xl shadow-md">
|
<div class="bg-white rounded-lg shadow-md p-6 border-blue-600 border-2 rounded-xl shadow-md dark:bg-transparent dark:text-white">
|
||||||
<form method="post" class="space-y-6" enctype="multipart/form-data">
|
<form method="post" class="space-y-6" enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<!-- Question Text -->
|
<!-- Question Text -->
|
||||||
<div>
|
<div>
|
||||||
<label for="question" class="block text-sm font-medium text-gray-700">Frage</label>
|
<label for="question" class="block text-sm font-medium text-gray-700 dark:text-white">Frage</label>
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
<textarea name="question" id="question" rows="4"
|
<textarea name="question" id="question" rows="4"
|
||||||
class="shadow-sm focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
class="dark:bg-[#2a2f3a] shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
||||||
required>{{ question.data.question }}</textarea>
|
required>{{ question.data.question }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -33,31 +33,31 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<div>
|
<div>
|
||||||
<label class="font-bold" for="question_image">Bild:</label>
|
<label class="font-bold" for="question_image">Bild:</label>
|
||||||
<input class="bg-blue-200 p-2 m-2 rounded-lg border-2 border-blue-400" type="file" name="question_image" id="question_image">
|
<input class="max-w-full bg-blue-200 p-2 m-2 rounded-lg border-2 border-blue-400 dark:bg-transparent" type="file" name="question_image" id="question_image">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- True/False Selection -->
|
<!-- True/False Selection -->
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Richtige Antwort</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2 dark:text-white">Richtige Antwort</label>
|
||||||
<div class="flex space-x-4">
|
<div class="flex space-x-4">
|
||||||
<label class="inline-flex items-center">
|
<label class="inline-flex items-center">
|
||||||
<input type="radio" name="correct_answer" value="true"
|
<input type="radio" name="correct_answer" value="true"
|
||||||
class="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300"
|
class="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300"
|
||||||
{% if question.data.correct_answer %}checked{% endif %}>
|
{% if question.data.correct_answer %}checked{% endif %}>
|
||||||
<span class="ml-2 text-sm text-gray-600">Wahr</span>
|
<span class="ml-2 text-sm text-gray-600 dark:text-white">Wahr</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="inline-flex items-center">
|
<label class="inline-flex items-center">
|
||||||
<input type="radio" name="correct_answer" value="false"
|
<input type="radio" name="correct_answer" value="false"
|
||||||
class="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300"
|
class="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300"
|
||||||
{% if not question.data.correct_answer %}checked{% endif %}>
|
{% if not question.data.correct_answer %}checked{% endif %}>
|
||||||
<span class="ml-2 text-sm text-gray-600">Falsch</span>
|
<span class="ml-2 text-sm text-gray-600 dark:text-white">Falsch</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<label class="font-bold" for="time_per_question">Zeit pro Frage:</label>
|
<label class="font-bold" for="time_per_question">Zeit pro Frage:</label>
|
||||||
<select name="time_per_question" id="time_per_question">
|
<select name="time_per_question" id="time_per_question" class="dark:text-white dark:bg-[#2a2f3a] focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||||
<option value="10" {% if standard_time_per_question == "10" or time_per_question == "10" %}selected{% endif %}>10 Sekunden</option>
|
<option value="10" {% if standard_time_per_question == "10" or time_per_question == "10" %}selected{% endif %}>10 Sekunden</option>
|
||||||
<option value="20" {% if standard_time_per_question == "20" or time_per_question == "20" %}selected{% endif %}>20 Sekunden</option>
|
<option value="20" {% if standard_time_per_question == "20" or time_per_question == "20" %}selected{% endif %}>20 Sekunden</option>
|
||||||
<option value="30" {% if standard_time_per_question == "30" or time_per_question == "30" %}selected{% endif %}>30 Sekunden</option>
|
<option value="30" {% if standard_time_per_question == "30" or time_per_question == "30" %}selected{% endif %}>30 Sekunden</option>
|
||||||
@@ -67,6 +67,13 @@
|
|||||||
<option value="300" {% if standard_time_per_question == "300" or time_per_question == "300" %}selected{% endif %}>5 Minuten</option>
|
<option value="300" {% if standard_time_per_question == "300" or time_per_question == "300" %}selected{% endif %}>5 Minuten</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<label for="credits" class="block text-sm font-medium text-gray-700 dark:text-white">Credits</label>
|
||||||
|
<div class="mt-1">
|
||||||
|
<textarea name="credits" rows="4"
|
||||||
|
class="dark:bg-[#2a2f3a] shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
||||||
|
>{{ credits }}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="flex justify-end space-x-3">
|
<div class="flex justify-end space-x-3">
|
||||||
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="grid place-content-center gap-2 w-full mt-4">
|
<div class="grid place-content-center gap-2 w-full mt-4">
|
||||||
<div class="flex space-x-2 pb-4">
|
<div class="flex space-x-2 pb-4">
|
||||||
<p class="text-sm font-extralight"><a href="/impress">Impressum</a></p>
|
<p class="text-sm font-extralight dark:text-white"><a href="/impress">Impressum</a></p>
|
||||||
<p class="text-sm font-extralight"><a href="/privacy">Datenschutz</a></p>
|
<p class="text-sm font-extralight dark:text-white"><a href="/privacy">Datenschutz</a></p>
|
||||||
<p class="text-sm font-extralight"><a href="https://edugit.org/enrichment-2024/qivip">Repository</a></p>
|
<p class="text-sm font-extralight dark:text-white"><a href="https://edugit.org/enrichment-2024/qivip">Repository</a></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
<!-- Desktop Search (centered on screen) - Hidden on mobile -->
|
<!-- Desktop Search (centered on screen) - Hidden on mobile -->
|
||||||
<div class="hidden md:flex justify-center items-center absolute left-1/2 transform -translate-x-1/2 min-w-40 ">
|
<div class="hidden md:flex justify-center items-center absolute left-1/2 transform -translate-x-1/2 min-w-40 ">
|
||||||
<form method="get" action="{% url 'library:overview_quiz' %}" class="mr-2 ml-2 flex items-center justify-center w-screen max-w-sm bg-white rounded-full px-4 py-1 shadow-md">
|
<form method="get" action="{% url link|default:'library:overview_quiz' %}" class="mr-2 ml-2 flex items-center justify-center w-screen max-w-sm bg-white rounded-full px-4 py-1 shadow-md dark:bg-gray-900">
|
||||||
<input id="quiz-search-desktop" list="quiz-names-desktop" type="text" name="search" placeholder="Suche ..." value="{{ request.GET.search }}"
|
<input id="quiz-search-desktop" list="quiz-names-desktop" type="text" name="search" placeholder="Suche ..." value="{{ request.GET.search }}"
|
||||||
class="text-sm w-full px-3 py-1 text-black bg-transparent focus:outline-none lg:text-base">
|
class="text-sm w-full px-3 py-1 text-black bg-transparent focus:outline-none lg:text-base dark:text-white">
|
||||||
<button class="py-1 text-blue-600">
|
<button class="py-1 text-blue-600">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5 md:size-6">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5 md:size-6">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
|
||||||
@@ -51,10 +51,10 @@
|
|||||||
<div id="mobile-menu" class="hidden absolute w-full z-50 md:hidden opacity-0 transform -translate-y-2 transition-all duration-300 ">
|
<div id="mobile-menu" class="hidden absolute w-full z-50 md:hidden opacity-0 transform -translate-y-2 transition-all duration-300 ">
|
||||||
<div class="bg-blue-500 pt-3 pb-4 rounded-b-lg shadow-inner">
|
<div class="bg-blue-500 pt-3 pb-4 rounded-b-lg shadow-inner">
|
||||||
<!-- Search in mobile menu -->
|
<!-- Search in mobile menu -->
|
||||||
<form method="get" action="{% url 'library:overview_quiz' %}" class="px-4 mb-4">
|
<form method="get" action="{% url link|default:'library:overview_quiz' %}" class="px-4 mb-4 ">
|
||||||
<div class="flex items-center justify-center bg-white rounded-full px-4 py-2 shadow-md">
|
<div class="flex items-center justify-center bg-white rounded-full px-4 py-2 shadow-md dark:bg-gray-900">
|
||||||
<input id="quiz-search-mobile" list="quiz-names-mobile" type="text" name="search" placeholder="Suche ..." value="{{ request.GET.search }}"
|
<input id="quiz-search-mobile" list="quiz-names-mobile" type="text" name="search" placeholder="Suche ..." value="{{ request.GET.search }}"
|
||||||
class="w-full text-sm px-2 text-black bg-transparent focus:outline-none">
|
class="w-full text-sm px-2 text-black bg-transparent focus:outline-none dark:text-white">
|
||||||
<button class="text-blue-600">
|
<button class="text-blue-600">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||||
stroke="currentColor" class="size-5">
|
stroke="currentColor" class="size-5">
|
||||||
|
|||||||
@@ -4,16 +4,16 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mx-auto px-4">
|
<div class="container mx-auto px-4">
|
||||||
<div class="max-w-2xl mx-auto">
|
<div class="max-w-2xl mx-auto">
|
||||||
<div class="bg-white rounded-lg shadow-md p-8 mb-6">
|
<div class="bg-white rounded-lg shadow-md p-8 mb-6 dark:bg-transparent dark:text-white">
|
||||||
<div class="text-center mb-8">
|
<div class="text-center mb-8">
|
||||||
<h1 class="text-4xl font-bold text-blue-600 mb-4">Quiz beendet!</h1>
|
<h1 class="text-4xl font-bold text-blue-600 mb-4">Quiz beendet!</h1>
|
||||||
<p class="text-xl text-gray-600">Vielen Dank fürs Spielen!</p>
|
<p class="text-xl text-gray-600 dark:text-white">Vielen Dank fürs Spielen!</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if not is_host %}
|
{% if not is_host %}
|
||||||
{% if rating_enabled %}
|
{% if rating_enabled %}
|
||||||
<div class="bg-blue-50 rounded-lg p-6 mb-8">
|
<div class="bg-blue-50 rounded-lg p-6 mb-8 dark:bg-transparent ">
|
||||||
<h2 class="text-2xl font-bold text-blue-800 mb-4 text-center">Wie hat dir das Quiz gefallen?</h2>
|
<h2 class="text-2xl font-bold text-blue-800 mb-4 text-center dark:text-white">Wie hat dir das Quiz gefallen?</h2>
|
||||||
<div class="stars flex justify-center space-x-4 mb-4">
|
<div class="stars flex justify-center space-x-4 mb-4">
|
||||||
<i class="fas fa-star text-3xl transition-all duration-200 hover:scale-110" data-rating="1"></i>
|
<i class="fas fa-star text-3xl transition-all duration-200 hover:scale-110" data-rating="1"></i>
|
||||||
<i class="fas fa-star text-3xl transition-all duration-200 hover:scale-110" data-rating="2"></i>
|
<i class="fas fa-star text-3xl transition-all duration-200 hover:scale-110" data-rating="2"></i>
|
||||||
|
|||||||
@@ -1,21 +1,42 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{% if request.session.mode == "learn" %}
|
|
||||||
|
|
||||||
<div class="container mx-auto px-4">
|
<div class="container mx-auto px-4">
|
||||||
<div class="flex justify-end mb-4">
|
<div class="flex justify-end mb-4">
|
||||||
|
{% if request.session.mode == "learn" %}
|
||||||
<button onclick="leaveGame()" class="bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded">
|
<button onclick="leaveGame()" class="bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded">
|
||||||
Spiel verlassen
|
Spiel verlassen
|
||||||
</button>
|
</button>
|
||||||
</div>{% endif %}
|
{% endif %}
|
||||||
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
<button onclick="this.onclick=null; advanceToScores();" class="mx-2 bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded">
|
||||||
<p class="text-gray-700 font-bold text-xl mb-4">Frage {{ question_index|add:1 }} von {{ total_questions }}</p>
|
überspringen
|
||||||
<h1 class="text-3xl font-bold mb-6">{{ question_data.question }}</h1>
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="form_host" class="bg-white rounded-lg shadow-md p-4 mb-6 dark:bg-transparent dark:text-white">
|
||||||
|
<div class="flex justify-between mb-2">
|
||||||
|
<div class="flex gap-1 text-sm"><p class="text-sm">Frage</p>
|
||||||
|
<p class="text-gray-700 font-bold text-sm dark:text-white">{{ question_index|add:1 }}</p>
|
||||||
|
<p class="text-sm">von</p>
|
||||||
|
<p class="text-gray-700 font-bold text-sm dark:text-white">{{ total_questions }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-1 mb-2"><p class="text-sm">Antworten:</p> <p id="answer-count" class="text-gray-700 font-bold text-sm dark:text-white"></p></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h1 class="text-xl font-black mb-2 border-blue-500 border-4 p-4 text-center rounded-lg md:text-2xl lg:text-4xl">{{ question_data.question}}</h1>
|
||||||
|
|
||||||
{% if question_image %}
|
{% if question_image %}
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<img class="m-4 w-full max-w-[500px] " src="{{ question_image.image.url }}" alt="Bild der Frage">
|
<img class="m-4 max-h-[33vh] w-auto rounded-lg" src="{{ question_image.image.url }}" alt="Bild der Frage">
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if request.session.mode != "learn" %}
|
||||||
|
<div class="w-full bg-gray-300 rounded-full h-4">
|
||||||
|
<div id="time-bar" class="bg-blue-600 h-4 rounded-full transition-all duration-100 linear" style="width: 100%;"></div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@@ -23,24 +44,38 @@
|
|||||||
<div class="grid grid-cols-1 gap-4 mb-6">
|
<div class="grid grid-cols-1 gap-4 mb-6">
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="grid grid-cols-2 gap-4 mb-6">
|
<div class="grid grid-cols-2 gap-4 mb-6">
|
||||||
{% endif %}
|
|
||||||
{% if request.session.mode != "learn" %}
|
|
||||||
<div class="p-4 bg-blue-50 rounded-lg">
|
|
||||||
<p class="text-blue-600 text-xl mb-2">Verbleibende Zeit </p>
|
|
||||||
<p id="remaining-time" class="text-6xl font-bold text-blue-700">30</p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="p-4 bg-blue-50 rounded-lg">
|
|
||||||
<p class="text-blue-600 text-xl mb-2">Antworten</p>
|
|
||||||
<p id="answer-count" class="text-6xl font-bold text-blue-700">0/0</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% if question_data.type != "input" %}
|
{% if question_data.type != "input" %}
|
||||||
<div class="grid grid-cols-2 gap-4" id="options-container">
|
<div class="grid grid-cols-2 gap-4" id="options-container">
|
||||||
{% for option in question_data.options %}
|
{% for option in question_data.options %}
|
||||||
<button
|
<button
|
||||||
class="p-4 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option"
|
class="
|
||||||
|
{% if forloop.counter0 == 0 %}
|
||||||
|
bg-green-500
|
||||||
|
hover:bg-green-600
|
||||||
|
{% elif forloop.counter0 == 1 %}
|
||||||
|
bg-red-500
|
||||||
|
hover:bg-red-600
|
||||||
|
{% elif forloop.counter0 == 2 %}
|
||||||
|
bg-blue-500
|
||||||
|
hover:bg-blue-600
|
||||||
|
{% elif forloop.counter0 == 3 %}
|
||||||
|
bg-purple-500
|
||||||
|
hover:bg-purple-600
|
||||||
|
{% elif forloop.counter0 == 4 %}
|
||||||
|
bg-orange-500
|
||||||
|
hover:bg-orange-600
|
||||||
|
{% elif forloop.counter0 == 5 %}
|
||||||
|
bg-yellow-500
|
||||||
|
hover:bg-yellow-600
|
||||||
|
{% else %}
|
||||||
|
bg-gray-500
|
||||||
|
hover:bg-gray-600
|
||||||
|
{% endif %}
|
||||||
|
p-4 rounded-lg text-white transition-colors duration-200 answer-option overflow-auto break-words hyphens-auto "
|
||||||
data-index="{{ forloop.counter0 }}"
|
data-index="{{ forloop.counter0 }}"
|
||||||
{% if request.session.mode == "learn" %}
|
{% if request.session.mode == "learn" %}
|
||||||
onclick="submitAnswer({{ forloop.counter0 }});" {% endif %}>
|
onclick="submitAnswer({{ forloop.counter0 }});" {% endif %}>
|
||||||
@@ -52,11 +87,11 @@
|
|||||||
{% if request.session.mode == "learn" %}
|
{% if request.session.mode == "learn" %}
|
||||||
<form action="">
|
<form action="">
|
||||||
<input id="textanswer" type="text" placeholder="DEINE ANTWORT"
|
<input id="textanswer" type="text" placeholder="DEINE ANTWORT"
|
||||||
class="answer-option text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option lg:w-80 ">
|
class="answer-option text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option lg:w-80 dark:bg-transparent dark:text-white dark:hover:bg-[#2a2f3a] ">
|
||||||
|
|
||||||
<button {% if request.session.mode == "learn" %}
|
<button {% if request.session.mode == "learn" %}
|
||||||
onclick="submitAnswer( -1 );" {% endif %}
|
onclick="submitAnswer( -1 );" {% endif %}
|
||||||
class="mt-2 text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option">
|
class="mt-2 text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option dark:bg-transparent dark:text-white dark:hover:bg-[#2a2f3a] ">
|
||||||
abschicken
|
abschicken
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
@@ -97,6 +132,7 @@
|
|||||||
data.action === 'show_scores' &&
|
data.action === 'show_scores' &&
|
||||||
data.redirect_url) {
|
data.redirect_url) {
|
||||||
window.location.href = data.redirect_url;
|
window.location.href = data.redirect_url;
|
||||||
|
submitAnswer( -1 );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -124,6 +160,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function advanceToScores() {
|
function advanceToScores() {
|
||||||
// Show correct answers and answer counts
|
// Show correct answers and answer counts
|
||||||
var correctOptions = document.querySelectorAll('[data-correct="True"]');
|
var correctOptions = document.querySelectorAll('[data-correct="True"]');
|
||||||
@@ -151,9 +188,14 @@
|
|||||||
function updateTimer() {
|
function updateTimer() {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const elapsed = now - questionStartTime;
|
const elapsed = now - questionStartTime;
|
||||||
const remaining = Math.max(0, Math.ceil((questionDuration - elapsed) / 1000));
|
const remaining = Math.max(0, (questionDuration - elapsed) / 1000);
|
||||||
|
|
||||||
document.getElementById('remaining-time').textContent = remaining;
|
|
||||||
|
//document.getElementById('remaining-time').textContent = remaining;
|
||||||
|
|
||||||
|
document.getElementById('time-bar').style.width = ((remaining * 1000) / questionDuration * 100) + '%';
|
||||||
|
if (remaining<3){
|
||||||
|
document.getElementById('time-bar').style.backgroundColor="red";}else if(remaining<5){document.getElementById('time-bar').style.backgroundColor="orange";}
|
||||||
|
|
||||||
if (remaining === 0) {
|
if (remaining === 0) {
|
||||||
advanceToScores();
|
advanceToScores();
|
||||||
|
|||||||
@@ -7,19 +7,49 @@
|
|||||||
Spiel verlassen
|
Spiel verlassen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
<div class="bg-white rounded-lg shadow-md p-6 mb-6 dark:bg-transparent dark:text-white">
|
||||||
<p class="text-gray-700 font-bold text-xl mb-4">Frage {{ question_index|add:1 }} von {{ total_questions }}</p>
|
|
||||||
<h1 class="text-3xl font-bold mb-6">{{ question_data.question }}</h1>
|
|
||||||
|
|
||||||
<div class="p-4 bg-blue-50 rounded-lg mb-6">
|
<div class="flex justify-between mb-2">
|
||||||
<p class="text-blue-600 text-xl mb-2">Verbleibende Zeit</p>
|
<div class="flex gap-1 text-sm"><p class="text-sm">Frage</p>
|
||||||
<p id="remaining-time" class="text-6xl font-bold text-blue-700">30</p>
|
<p class="text-gray-700 font-bold text-sm dark:text-white">{{ question_index|add:1 }}</p>
|
||||||
|
<p class="text-sm">von</p>
|
||||||
|
<p class="text-gray-700 font-bold text-sm dark:text-white">{{ total_questions }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-xl font-black mb-2 border-blue-500 border-4 p-4 text-center rounded-lg md:text-2xl lg:text-4xl">{{ question_data.question}}</h1>
|
||||||
|
|
||||||
|
<div class="w-full bg-gray-300 rounded-full h-4 my-4">
|
||||||
|
<div id="time-bar" class="bg-blue-600 h-4 rounded-full transition-all duration-100 linear" style="width: 100%;"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if question_data.type != "input" %}
|
{% if question_data.type != "input" %}
|
||||||
<div class="grid grid-cols-2 gap-4" id="options-container">
|
<div class="grid grid-cols-2 gap-4" id="options-container">
|
||||||
{% for option in question_data.options %}
|
{% for option in question_data.options %}
|
||||||
<button
|
<button
|
||||||
class="p-4 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option"
|
class="
|
||||||
|
{% if forloop.counter0 == 0 %}
|
||||||
|
bg-green-500
|
||||||
|
hover:bg-green-600
|
||||||
|
{% elif forloop.counter0 == 1 %}
|
||||||
|
bg-red-500
|
||||||
|
hover:bg-red-600
|
||||||
|
{% elif forloop.counter0 == 2 %}
|
||||||
|
bg-blue-500
|
||||||
|
hover:bg-blue-600
|
||||||
|
{% elif forloop.counter0 == 3 %}
|
||||||
|
bg-purple-500
|
||||||
|
hover:bg-purple-600
|
||||||
|
{% elif forloop.counter0 == 4 %}
|
||||||
|
bg-orange-500
|
||||||
|
hover:bg-orange-600
|
||||||
|
{% elif forloop.counter0 == 5 %}
|
||||||
|
bg-yellow-500
|
||||||
|
hover:bg-yellow-600
|
||||||
|
{% else %}
|
||||||
|
bg-gray-500
|
||||||
|
hover:bg-gray-600
|
||||||
|
{% endif %}
|
||||||
|
p-4 rounded-lg text-white transition-colors duration-200 answer-option overflow-auto break-words hyphens-auto "
|
||||||
data-index="{{ forloop.counter0 }}"
|
data-index="{{ forloop.counter0 }}"
|
||||||
onclick="submitAnswer({{ forloop.counter0 }});">
|
onclick="submitAnswer({{ forloop.counter0 }});">
|
||||||
<p class="text-lg">{{ option.value }}</p>
|
<p class="text-lg">{{ option.value }}</p>
|
||||||
@@ -29,10 +59,10 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<form action="">
|
<form action="">
|
||||||
<input id="textanswer" type="text" placeholder="DEINE ANTWORT"
|
<input id="textanswer" type="text" placeholder="DEINE ANTWORT"
|
||||||
class="answer-option text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option lg:w-80">
|
class="answer-option text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option lg:w-80 dark:bg-transparent dark:text-white dark:hover:bg-[#2a2f3a]">
|
||||||
<button
|
<button
|
||||||
onclick="submitAnswer( -1 );"
|
onclick="submitAnswer( -1 );"
|
||||||
class="mt-2 text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option">
|
class="mt-2 text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option dark:bg-transparent dark:text-white dark:hover:bg-[#2a2f3a]">
|
||||||
abschicken
|
abschicken
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
@@ -47,7 +77,7 @@
|
|||||||
let hasAnswered = false;
|
let hasAnswered = false;
|
||||||
const joinCode = '{{ quiz_game.join_code }}';
|
const joinCode = '{{ quiz_game.join_code }}';
|
||||||
const participantId = '{{ participant.participant_id }}';
|
const participantId = '{{ participant.participant_id }}';
|
||||||
const questionStartTime = {{ start_time }};
|
const questionStartTime = Date.now();
|
||||||
const questionDuration = '{{ current_question.time_per_question }}'*1000; //Zeit pro Frage (indviduell eingestellt)
|
const questionDuration = '{{ current_question.time_per_question }}'*1000; //Zeit pro Frage (indviduell eingestellt)
|
||||||
const gameSocket = initializeGameSocket(joinCode);
|
const gameSocket = initializeGameSocket(joinCode);
|
||||||
|
|
||||||
@@ -59,6 +89,7 @@
|
|||||||
data.action === 'show_scores' &&
|
data.action === 'show_scores' &&
|
||||||
data.redirect_url) {
|
data.redirect_url) {
|
||||||
window.location.href = data.redirect_url;
|
window.location.href = data.redirect_url;
|
||||||
|
submitAnswer( -1 );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -118,9 +149,13 @@
|
|||||||
function updateTimer() {
|
function updateTimer() {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const elapsed = now - questionStartTime;
|
const elapsed = now - questionStartTime;
|
||||||
const remaining = Math.max(0, Math.ceil((questionDuration - elapsed) / 1000));
|
const remaining = Math.max(0, (questionDuration - elapsed) / 1000);
|
||||||
|
document.getElementById('time-bar').style.width = ((remaining * 1000) / questionDuration * 100) + '%';
|
||||||
|
if (remaining<3){
|
||||||
|
document.getElementById('time-bar').style.backgroundColor="red";}else if(remaining<5){document.getElementById('time-bar').style.backgroundColor="orange";}
|
||||||
|
|
||||||
document.getElementById('remaining-time').textContent = remaining;
|
|
||||||
|
//document.getElementById('remaining-time').textContent = remaining;
|
||||||
|
|
||||||
if (remaining === 0 && !hasAnswered) {
|
if (remaining === 0 && !hasAnswered) {
|
||||||
// Auto-submit timeout answer
|
// Auto-submit timeout answer
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mx-auto px-4">
|
<div class="container mx-auto px-4">
|
||||||
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
<div class="bg-white rounded-lg shadow-md p-6 mb-6 dark:bg-transparent dark:text-white">
|
||||||
<h1 class="text-3xl font-bold mb-6">Ergebnisse</h1>
|
<h1 class="text-3xl font-bold mb-6">Ergebnisse</h1>
|
||||||
|
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
@@ -11,12 +11,12 @@
|
|||||||
<div class="grid grid-cols-2 gap-4">
|
<div class="grid grid-cols-2 gap-4">
|
||||||
{% for option in question_data.options %}
|
{% for option in question_data.options %}
|
||||||
|
|
||||||
<div id="option-box-{{ forloop.counter0 }}" class="bg-gray-100 relative p-4 rounded-lg overflow-hidden {% if option.is_correct %} border-2 border-green-500{% else %}border-2 border-red-500{% endif %}">
|
<div id="option-box-{{ forloop.counter0 }}" class=" dark:bg-transparent relative p-4 rounded-lg overflow-auto break-words hyphens-auto {% if option.is_correct %} border-2 border-green-500{% else %}border-2 border-red-500{% endif %}">
|
||||||
|
|
||||||
<div id="option-fill-{{ forloop.counter0 }}" class="absolute left-0 top-0 h-full {% if option.is_correct %}bg-green-300 {% else %}bg-red-300 {% endif %} opacity-50 z-0 transition-all duration-1500 " style="width: 0%;"></div>
|
<div id="option-fill-{{ forloop.counter0 }}" class="absolute left-0 top-0 h-full {% if option.is_correct %}bg-green-300 {% else %}bg-red-300 {% endif %} opacity-50 z-0 transition-all duration-1500 " style="width: 0%;"></div>
|
||||||
<div class="relative z-10">
|
<div class="relative z-10">
|
||||||
<p class="text-lg ">{{ option.value }}</p>
|
<p class="text-lg ">{{ option.value }}</p>
|
||||||
<p class="text-gray-600" id="option-count-{{ forloop.counter0 }}">0 Antworten</p>
|
<p class="text-gray-600 dark:text-gray-400" id="option-count-{{ forloop.counter0 }}">0 Antworten</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
<div id="scoreboard" class="leading-relaxed">
|
<div id="scoreboard" class="leading-relaxed">
|
||||||
{% for participant in participants %}
|
{% for participant in participants %}
|
||||||
{% if participant == my_participant or is_host %}
|
{% if participant == my_participant or is_host %}
|
||||||
<div class="mt-2 shadow-sm p-4 bg-gray-100 rounded-lg border-2 border {% if forloop.counter <= 3 %}border-yellow-500{% else %}border-transparent{% endif %}">
|
<div class="dark:bg-transparent mt-2 shadow-sm p-4 bg-gray-100 rounded-lg border-2 border {% if forloop.counter <= 3 %}border-yellow-500{% else %}border-transparent{% endif %}">
|
||||||
<div class="flex flex-col items-start gap-1">
|
<div class="flex flex-col items-start gap-1">
|
||||||
<div class="text-lg font-bold flex items-center gap-2">
|
<div class="text-lg font-bold flex items-center gap-2">
|
||||||
{% if forloop.counter == 1 %}
|
{% if forloop.counter == 1 %}
|
||||||
@@ -42,10 +42,10 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
{{ forloop.counter }}.
|
{{ forloop.counter }}.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span class="display_name text-gray-600 font-black text-2xl " id="display_name-{{ forloop.counter0 }}">{{ participant.display_name }}</span>
|
<span class="display_name text-gray-600 font-black text-2xl dark:text-white " id="display_name-{{ forloop.counter0 }}">{{ participant.display_name }}</span>
|
||||||
</div class="flex flex-col items-start">
|
</div class="flex flex-col items-start">
|
||||||
|
|
||||||
<p data-score="{{ participant.score }}" data-last-score="{{ participant.last_score }}" class="text-gray-600 font-bold show-score" id="score-{{ forloop.counter0 }}">{{ participant.score }} Punkte</p>
|
<p data-score="{{ participant.score }}" data-last-score="{{ participant.last_score }}" class="dark:text-white text-gray-600 font-bold show-score" id="score-{{ forloop.counter0 }}">{{ participant.score }} Punkte</p>
|
||||||
{% if participant == my_participant or request.session.mode == "learn"%}
|
{% if participant == my_participant or request.session.mode == "learn"%}
|
||||||
<p class="text-blue-600 font-bold text-sm">+{{ participant.last_score }} Punkte</p>
|
<p class="text-blue-600 font-bold text-sm">+{{ participant.last_score }} Punkte</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
|
|
||||||
<div class=" pt-3 text-center text-gray-600 font-bold" id="antwort-richtig">
|
<div class="dark:text-white pt-3 text-center text-gray-600 font-bold" id="antwort-richtig">
|
||||||
Hier erscheint gleich dein Feedback...
|
Hier erscheint gleich dein Feedback...
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
|
|
||||||
<div class=" pt-3 text-center text-gray-600 font-bold" id="antwort-falsch">
|
<div class="dark:text-white pt-3 text-center text-gray-600 font-bold" id="antwort-falsch">
|
||||||
Hier erscheint gleich dein Feedback...
|
Hier erscheint gleich dein Feedback...
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-center border-t-2 border-gray-500 gap-1">
|
<div class="flex justify-center border-t-2 border-gray-500 gap-1">
|
||||||
@@ -181,9 +181,12 @@
|
|||||||
el.style.transform = 'translateY(20px)';
|
el.style.transform = 'translateY(20px)';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
try{
|
||||||
|
document.getElementById("finish-button").style.display = 'none';}
|
||||||
|
catch{}
|
||||||
|
|
||||||
// Warten bevor Animation startet
|
// Warten bevor Animation startet
|
||||||
await sleep(1500); // <<< hier die Pause
|
await sleep(500); // <<< hier die Pause
|
||||||
|
|
||||||
|
|
||||||
// Transition-Eigenschaft setzen nach Render-Zyklus
|
// Transition-Eigenschaft setzen nach Render-Zyklus
|
||||||
@@ -200,9 +203,13 @@
|
|||||||
|
|
||||||
if (index === top3.length - 1) {
|
if (index === top3.length - 1) {
|
||||||
triggerConfetti();
|
triggerConfetti();
|
||||||
|
try{
|
||||||
|
|
||||||
|
document.getElementById("finish-button").style.display = 'block';}
|
||||||
|
catch{}
|
||||||
|
|
||||||
}
|
}
|
||||||
}, index * 1500); // Zeitversetzt aufdecken
|
}, index * 1000); // Zeitversetzt aufdecken
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -337,7 +344,7 @@ if (antwortRichtig) {
|
|||||||
'type': 'next_question',
|
'type': 'next_question',
|
||||||
'host_id': hostId
|
'host_id': hostId
|
||||||
}));
|
}));
|
||||||
});
|
}, { once: true });
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mx-auto px-4 py-8">
|
<div class="container mx-auto px-4 py-8">
|
||||||
<div class="max-w-md mx-auto bg-white rounded-lg shadow-lg p-6">
|
<div class="max-w-md mx-auto bg-white rounded-lg shadow-lg p-6 dark:bg-transparent dark:border-2 dark:text-white">
|
||||||
<h1 class="text-2xl font-bold mb-6 text-center text-blue-600">Spieler einrichten</h1>
|
<h1 class="text-2xl font-bold mb-6 text-center text-blue-600">Spieler einrichten</h1>
|
||||||
|
|
||||||
<div class="text-center mb-6">
|
<div class="text-center mb-6">
|
||||||
@@ -17,20 +17,20 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="join_code" value="{{join_code}}">
|
<input type="hidden" name="join_code" value="{{join_code}}">
|
||||||
|
|
||||||
<div class="bg-gray-50 p-4 rounded-lg mb-4">
|
<div class="bg-gray-50 p-4 rounded-lg mb-4 dark:bg-transparent">
|
||||||
<p class="text-sm text-gray-600 mb-2">Wähle einen Anzeigenamen für das Spiel:</p>
|
<p class="text-sm text-gray-600 mb-2 dark:text-white">Wähle einen Anzeigenamen für das Spiel:</p>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
name="display_name"
|
name="display_name"
|
||||||
required
|
required
|
||||||
maxlength="20"
|
maxlength="20"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
placeholder="Dein Spielername">
|
placeholder="Dein Spielername">
|
||||||
<p class="text-xs text-gray-500 mt-2">Maximal 20 Zeichen</p>
|
<p class="text-xs text-gray-500 mt-2 dark:text-white">Maximal 20 Zeichen</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-center space-x-4">
|
<div class="flex justify-center space-x-4">
|
||||||
<a href="/"
|
<a href="/"
|
||||||
class="px-6 py-2 bg-gray-200 hover:bg-gray-300 rounded-lg transition-colors duration-200">
|
class="px-6 py-2 bg-gray-200 hover:bg-gray-300 rounded-lg transition-colors duration-200 dark:bg-transparent dark:hover:bg-[#2a2f3a]">
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</a>
|
</a>
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="sm:grid sm:place-items-center sm:min-h-[calc(100vh-5rem)] flex justify-center py-6 m-2">
|
<div class="sm:grid sm:place-items-center sm:min-h-[calc(100vh-5rem)] flex justify-center py-6 m-2">
|
||||||
<div class="max-w-md w-full p-8 rounded-2xl border-2 border-blue-400 bg-white">
|
<div class="max-w-md w-full p-8 rounded-2xl border-2 border-blue-400 bg-white dark:bg-transparent dark:text-white">
|
||||||
<h1 class="text-2xl text-center font-bold mb-4 ">Spiel beitreten</h1>
|
<h1 class="text-2xl text-center font-bold mb-4 ">Spiel beitreten</h1>
|
||||||
<form action="{% url 'play:join_game' %}" method="post" class="flex flex-col gap-4">
|
<form action="{% url 'play:join_game' %}" method="post" class="flex flex-col gap-4">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="flex gap-3 items-center justify-center">
|
<div class="flex gap-3 items-center justify-center">
|
||||||
<input type="number" name="game_code" placeholder="123456" maxlength="6" class="w-32 p-3 rounded-full bg-gray-200 focus:scale-105 transition duration-200 font-black focus:outline-none focus:ring-2 focus:ring-blue-400 focus:bg-blue-100 text-center tracking-wider" autofocus>
|
<input type="number" name="game_code" placeholder="123456" maxlength="6" class="w-32 p-3 rounded-full bg-gray-200 focus:scale-105 transition duration-200 font-black focus:outline-none focus:ring-2 focus:ring-blue-400 focus:bg-blue-100 text-center tracking-wider text-black" autofocus>
|
||||||
<button type="submit" class="h-12 px-6 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed hover:bg-blue-700 active:scale-95 group" disabled>
|
<button type="submit" class="h-12 px-6 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed hover:bg-blue-700 active:scale-95 group" disabled>
|
||||||
<span class="hidden sm:block">Beitreten</span>
|
<span class="hidden sm:block">Beitreten</span>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 transition-transform group-hover:translate-x-1">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 transition-transform group-hover:translate-x-1">
|
||||||
|
|||||||
@@ -3,18 +3,18 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mx-auto px-4 py-8">
|
<div class="container mx-auto px-4 py-8">
|
||||||
|
|
||||||
<div class="max-w-2xl mx-auto bg-white rounded-lg shadow-lg p-6">
|
<div class="max-w-2xl mx-auto bg-white rounded-lg shadow-lg p-6 dark:bg-transparent dark:text-white">
|
||||||
<!-- Quiz Info -->
|
<!-- Quiz Info -->
|
||||||
<div class="text-center mb-8">
|
<div class="text-center mb-8">
|
||||||
<h3 class="text-xl text-gray-600 mb-2">{{ quiz.name }}</h3>
|
<h3 class="text-xl text-gray-600 mb-2 dark:text-white">{{ quiz.name }}</h3>
|
||||||
{% if request.session.mode != "learn" %}
|
{% if request.session.mode != "learn" %}
|
||||||
{% if host_id %}
|
{% if host_id %}
|
||||||
<div class="bg-blue-100 rounded-lg p-4 mb-4">
|
<div class="bg-blue-100 rounded-lg p-4 mb-4 dark:bg-transparent">
|
||||||
<h1 class="text-4xl font-bold text-blue-800">{{ quiz_game.join_code }}</h1>
|
<h1 class="text-4xl font-bold text-blue-800 dark:text-white">{{ quiz_game.join_code }}</h1>
|
||||||
<div class="w-full flex justify-center my-2">
|
<div class="w-full flex justify-center my-2">
|
||||||
<img src="data:image/png;base64,{{ qr_code_base64 }}" class="h-1/2 w-1/2" alt="QR-Code">
|
<img src="data:image/png;base64,{{ qr_code_base64 }}" class="h-1/2 w-1/2" alt="QR-Code">
|
||||||
</div>
|
</div>
|
||||||
<p class="text-sm text-blue-600 mt-1">Spiel-Code</p>
|
<p class="text-sm text-blue-600 mt-1 dark:text-white">Spiel-Code</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<!-- Participant Info -->
|
<!-- Participant Info -->
|
||||||
{% if participant %}
|
{% if participant %}
|
||||||
<div class="mb-6 text-center">
|
<div class="mb-6 text-center">
|
||||||
<div class="inline-flex items-center bg-green-100 px-4 py-2 rounded-full">
|
<div class="inline-flex items-center bg-green-100 px-4 py-2 rounded-full dark:text-black">
|
||||||
<span class="w-2 h-2 bg-green-500 rounded-full mr-2 "></span>
|
<span class="w-2 h-2 bg-green-500 rounded-full mr-2 "></span>
|
||||||
<span>Angemeldet als <b>{{ participant.display_name }}</b></span>
|
<span>Angemeldet als <b>{{ participant.display_name }}</b></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- Participants List -->
|
<!-- Participants List -->
|
||||||
<div class="mb-6 overflow-y-scroll max-h-96">
|
<div class="mb-6 overflow-y-scroll max-h-96 overflow-x-hidden">
|
||||||
<h3 class="font-bold text-lg mb-3 flex items-center">
|
<h3 class="font-bold text-lg mb-3 flex items-center">
|
||||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
Teilnehmer
|
Teilnehmer
|
||||||
</h3>
|
</h3>
|
||||||
<ul id="participants-list" class="space-y-2 max-h-60 ">
|
<ul id="participants-list" class="space-y-2 max-h-60 ">
|
||||||
<li class="text-gray-500 p-3 bg-gray-50 rounded-lg text-center">Warte auf Teilnehmer...</li>
|
<li class=" p-3 bg-gray-50 rounded-lg text-center dark:bg-transparent">Warte auf Teilnehmer...</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -248,7 +248,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!participants || participants.length === 0) {
|
if (!participants || participants.length === 0) {
|
||||||
list.innerHTML = '<li class="text-gray-500 p-3 bg-gray-50 rounded-lg text-center">Noch keine Teilnehmer...</li>';
|
list.innerHTML = '<li class="text-gray-500 p-3 bg-gray-50 rounded-lg text-center dark:bg-transparent">Noch keine Teilnehmer...</li>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,13 +298,13 @@
|
|||||||
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' +
|
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" ' +
|
||||||
'd="M6 18L18 6M6 6l12 12"/>' +
|
'd="M6 18L18 6M6 6l12 12"/>' +
|
||||||
'</svg>' +
|
'</svg>' +
|
||||||
'<span class="absolute -top-8 left-1/2 transform -translate-x-1/2 px-2 py-1 ' +
|
'<span class="absolute pr-8 -top-8 left-1/2 transform -translate-x-1/2 px-2 py-1 ' +
|
||||||
'bg-gray-800 text-white text-xs rounded opacity-0 group-hover:opacity-100 ' +
|
'bg-gray-800 text-white text-xs rounded opacity-0 group-hover:opacity-100 ' +
|
||||||
'transition-opacity duration-200 whitespace-nowrap">Spieler kicken</span>' +
|
'transition-opacity duration-200 whitespace-nowrap">Spieler kicken</span>' +
|
||||||
'</button>';
|
'</button>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<li class="p-3 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md transition duration-200 flex items-center justify-between animate-fade-in">' +
|
return '<li class="dark:bg-transparent p-3 bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md transition duration-200 flex items-center justify-between animate-fade-in">' +
|
||||||
'<div class="flex items-center">' +
|
'<div class="flex items-center">' +
|
||||||
'<div class="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center mr-3">' +
|
'<div class="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center mr-3">' +
|
||||||
'<span class="text-blue-600 font-bold">' + initial.toUpperCase() + '</span>' +
|
'<span class="text-blue-600 font-bold">' + initial.toUpperCase() + '</span>' +
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<div class="grid place-content-center md:h-screen h-150 w-full -z-50 top-0 p-8 ">
|
<div class="grid place-content-center md:h-screen h-150 w-full -z-50 top-0 p-8 ">
|
||||||
<div class="rounded-md rounded-xl shadow-lg border-3 border-blue-100 p-10">
|
<div class="rounded-md rounded-xl shadow-lg border-3 border-blue-100 p-10">
|
||||||
<span class="flex justify-center font-bold p-4 text-center text-1xl lg:text-2xl">Bitte wählen Sie einen Spielmodus aus:</span>
|
<span class="flex justify-center font-bold p-4 text-center text-1xl lg:text-2xl dark:text-white">Bitte wählen Sie einen Spielmodus aus:</span>
|
||||||
|
|
||||||
<div class="grid sm:grid-cols-2 place-items-stretch text-center gap-4 p-4">
|
<div class="grid sm:grid-cols-2 place-items-stretch text-center gap-4 p-4">
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,15 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container mx-auto px-4">
|
<div class="container mx-auto px-4">
|
||||||
<div class="max-w-lg mx-auto mt-10">
|
<div class="max-w-lg mx-auto mt-10">
|
||||||
<div class="bg-white rounded-lg shadow-md p-6 border-blue-600 border-2 rounded-xl shadow-md">
|
<div class="bg-white rounded-lg shadow-md p-6 border-blue-600 border-2 rounded-xl shadow-md dark:text-white dark:bg-transparent">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<svg class="mx-auto h-12 w-12 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="mx-auto h-12 w-12 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<h2 class="mt-4 text-xl font-bold text-gray-900">Löschen bestätigen</h2>
|
<h2 class="mt-4 text-xl font-bold text-gray-900 dark:text-white">Löschen bestätigen</h2>
|
||||||
|
|
||||||
<p class="mt-2 text-sm text-gray-600">
|
<p class="mt-2 text-sm text-gray-600 dark:text-white">
|
||||||
Möchten Sie ihren Account wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.
|
Möchten Sie ihren Account wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
{% block title %}Passwort ändern{% endblock %}
|
{% block title %}Passwort ändern{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="grid place-content-center h-120 mt-12 mb-12 ">
|
<div class="grid place-content-center h-120 mt-12 mb-12 ">
|
||||||
<div class="w-80 p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90">
|
<div class="w-80 p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90 dark:text-white!">
|
||||||
<h2 class="text-2xl text-center p-4 font-black">Passwort ändern</h2>
|
<h2 class="text-2xl text-center p-4 font-black">Passwort ändern</h2>
|
||||||
<form class="space-y-4" method="post">
|
<form class="space-y-4" method="post">
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
@@ -21,17 +21,17 @@
|
|||||||
<div class="register">
|
<div class="register">
|
||||||
|
|
||||||
{{ form.old_password.label_tag }}
|
{{ form.old_password.label_tag }}
|
||||||
<input type="password" name="old_password" placeholder="ALTES PASSWORT" />
|
<input type="password" name="old_password" placeholder="ALTES PASSWORT" class="dark:text-black" />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="register">
|
<div class="register">
|
||||||
{{ form.new_password1.label_tag }}
|
{{ form.new_password1.label_tag }}
|
||||||
<input type="password" name="new_password1" placeholder="NEUES PASSWORT" />
|
<input type="password" name="new_password1" placeholder="NEUES PASSWORT" class="dark:text-black" />
|
||||||
</div>
|
</div>
|
||||||
<div class="register">
|
<div class="register">
|
||||||
{{ form.new_password2.label_tag }}
|
{{ form.new_password2.label_tag }}
|
||||||
<input type="password" name="new_password2" placeholder="NEUES PASSWORT WIEDERHOLEN" />
|
<input type="password" name="new_password2" placeholder="NEUES PASSWORT WIEDERHOLEN" class="dark:text-black" />
|
||||||
</div>
|
</div>
|
||||||
<button class="w-full p-3 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200" type="submit">Bestätigen</button>
|
<button class="w-full p-3 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200" type="submit">Bestätigen</button>
|
||||||
<button class="text-center text-sm w-full mt-2 font-light text-blue-600"><a href="{% url 'accounts:home' %}" class="register_link">Doch nicht ändern?</a></button>
|
<button class="text-center text-sm w-full mt-2 font-light text-blue-600"><a href="{% url 'accounts:home' %}" class="register_link">Doch nicht ändern?</a></button>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
{% block title %}Passwort zurückgesetzt{% endblock %}
|
{% block title %}Passwort zurückgesetzt{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="grid place-content-center h-120 mt-12 mb-12 ">
|
<div class="grid place-content-center h-120 mt-12 mb-12 ">
|
||||||
<div class="w-80 p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90">
|
<div class="w-80 p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90 dark:text-white">
|
||||||
<h2 class="text-2xl text-center p-4 font-black">Passwort zurückgesetzt</h2>
|
<h2 class="text-2xl text-center p-4 font-black">Passwort zurückgesetzt</h2>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
Das Passwort wurde erfolgreich zurückgesetzt! Sie können sich nun mit dem neuen Passwort anmelden!
|
Das Passwort wurde erfolgreich zurückgesetzt! Sie können sich nun mit dem neuen Passwort anmelden!
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="grid place-content-center h-120 mt-12 mb-12 ">
|
<div class="grid place-content-center h-120 mt-12 mb-12 ">
|
||||||
<div class="w-80 p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90">
|
<div class="w-80 p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90">
|
||||||
<h2 class="text-2xl text-center p-4 font-black">Passwort zurücksetzen</h2>
|
<h2 class="text-2xl text-center p-4 font-black dark:text-white">Passwort zurücksetzen</h2>
|
||||||
{% if validlink %}
|
{% if validlink %}
|
||||||
<form class="space-y-4" method="post">
|
<form class="space-y-4" method="post">
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
@@ -21,11 +21,12 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<div class="register">
|
<div class="register">
|
||||||
{{ form.new_password1.label_tag }}
|
|
||||||
|
<span class="dark:text-white">{{ form.new_password1.label_tag }} </span>
|
||||||
<input type="password" name="new_password1" placeholder="NEUES PASSWORT" />
|
<input type="password" name="new_password1" placeholder="NEUES PASSWORT" />
|
||||||
</div>
|
</div>
|
||||||
<div class="register ">
|
<div class="register ">
|
||||||
{{ form.new_password2.label_tag }}
|
<span class="dark:text-white">{{ form.new_password2.label_tag }} </span>
|
||||||
<input type="password" name="new_password2" placeholder="NEUES PASSWORT WIEDERHOLEN" />
|
<input type="password" name="new_password2" placeholder="NEUES PASSWORT WIEDERHOLEN" />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="grid place-content-center h-120 mt-12 mb-12">
|
<div class="grid place-content-center h-120 mt-12 mb-12">
|
||||||
<div class="w-80 p-6 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90 text-center">
|
<div class="w-80 p-6 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90 text-center dark:text-white">
|
||||||
<h2 class="text-2xl font-black mb-4">E-Mail wurde gesendet</h2>
|
<h2 class="text-2xl font-black mb-4 dark:text-white">E-Mail wurde gesendet</h2>
|
||||||
<p class="text-gray-700 mb-6">
|
<p class="text-gray-700 mb-6 dark:text-white">
|
||||||
Wenn ein Konto mit dieser E-Mail-Adresse existiert, haben wir dir eine Nachricht mit einem Link zum Zurücksetzen des Passworts gesendet.
|
Wenn ein Konto mit dieser E-Mail-Adresse existiert, haben wir dir eine Nachricht mit einem Link zum Zurücksetzen des Passworts gesendet.
|
||||||
|
|
||||||
</p><p class="text-gray-700 mb-6 font-bold"> Tipp: Gegebenenfalls Spam überprüfen.</p>
|
</p><p class="text-gray-700 mb-6 font-bold dark:text-white"> Tipp: Gegebenenfalls Spam überprüfen.</p>
|
||||||
|
|
||||||
|
|
||||||
<a href="{% url 'accounts:login' %}" class="block w-full p-3 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200">Zur Anmeldung</a>
|
<a href="{% url 'accounts:login' %}" class="block w-full p-3 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200">Zur Anmeldung</a>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
{% block title %}Passwort ändern{% endblock %}
|
{% block title %}Passwort ändern{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="grid place-content-center h-120 mt-12 mb-12 ">
|
<div class="grid place-content-center h-120 mt-12 mb-12 ">
|
||||||
<div class="w-80 p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90">
|
<div class="w-80 p-4 m-2 border-blue-600 border-2 rounded-xl shadow-md lg:w-90 dark:text-white">
|
||||||
<h2 class="text-2xl text-center p-4 font-black">Passwort zurücksetzen</h2>
|
<h2 class="text-2xl text-center p-4 font-black">Passwort zurücksetzen</h2>
|
||||||
<form class="space-y-4" method="post">
|
<form class="space-y-4" method="post">
|
||||||
Gib hier deine E-Mail an und erhalte eine E-Mail, um das Passwort zurückzusetzen.
|
Gib hier deine E-Mail an und erhalte eine E-Mail, um das Passwort zurückzusetzen.
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
<div class="register">
|
<div class="register">
|
||||||
{{ form.email.label_tag }}
|
{{ form.email.label_tag }}
|
||||||
<input type="email" name="email" placeholder="E-MAIL" />
|
<input type="email" name="email" placeholder="E-MAIL" class="dark:text-black" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user