Compare commits
35 Commits
88-avatare
...
123-reakti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c66e22a436 | ||
|
|
fbec1fed05 | ||
|
|
169f9b41a1 | ||
|
|
75e25fb3df | ||
|
|
e1d4f145f0 | ||
| 7eb2a80656 | |||
| 3aaf684b0e | |||
|
|
9199678b4b | ||
|
|
5d8f3ed820 | ||
| a5d4e75040 | |||
| 7e4bb05c74 | |||
| 1bb2666784 | |||
|
|
c05c3fd4a0 | ||
|
|
c9a1342f1d | ||
|
|
991488790a | ||
|
|
c014003062 | ||
|
|
8133eaa439 | ||
| 38a2ffcaff | |||
|
|
cfa95a84e7 | ||
|
|
64e89d3749 | ||
|
|
2708be3177 | ||
|
|
647b45d8a6 | ||
|
|
c8e2817b07 | ||
|
|
01e7909e3a | ||
| dfee602d54 | |||
|
|
0062f88167 | ||
|
|
de3d3dd00c | ||
|
|
85ba8bc9cb | ||
|
|
a8103b4a20 | ||
|
|
ba3e89f9f7 | ||
|
|
dbc457b21d | ||
|
|
a6cac52ba6 | ||
|
|
5f10c2a57b | ||
|
|
19092b092d | ||
|
|
2ca623bf33 |
7
datenschutzerklaerung.txt
Normal file
7
datenschutzerklaerung.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Name und Anschrift des Verantwortlichen
|
||||||
|
|
||||||
|
//NAME HIER EINSETZEN//
|
||||||
|
|
||||||
|
//ADRESSE HIER EINSETZEN//
|
||||||
|
|
||||||
|
//E-MAIL HIER EINSETZEN//
|
||||||
@@ -6,11 +6,15 @@ from django import forms
|
|||||||
class RegisterForm(UserCreationForm):
|
class RegisterForm(UserCreationForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model=User
|
model=User
|
||||||
fields = ['username','password1','password2']
|
fields = ['username','password1','password2', "email"]
|
||||||
|
|
||||||
username = forms.CharField(
|
username = forms.CharField(
|
||||||
widget=forms.TextInput(attrs={'placeholder': 'BENUTZERNAME'})
|
widget=forms.TextInput(attrs={'placeholder': 'BENUTZERNAME'})
|
||||||
)
|
)
|
||||||
|
email = forms.EmailField(
|
||||||
|
widget=forms.TextInput(attrs={'placeholder': 'E-MAIL'})
|
||||||
|
)
|
||||||
|
|
||||||
password1 = forms.CharField(
|
password1 = forms.CharField(
|
||||||
widget=forms.PasswordInput(attrs={'placeholder': 'PASSWORT'})
|
widget=forms.PasswordInput(attrs={'placeholder': 'PASSWORT'})
|
||||||
)
|
)
|
||||||
@@ -19,4 +23,3 @@ class RegisterForm(UserCreationForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
from django.urls import path # type: ignore
|
from django.urls import path, reverse_lazy # type: ignore
|
||||||
from . import views
|
from . import views
|
||||||
from django.contrib.auth.views import LogoutView
|
from django.contrib.auth.views import LogoutView
|
||||||
from django.contrib.auth.views import LoginView
|
from django.contrib.auth.views import LoginView
|
||||||
|
from django.contrib.auth import views as auth_views
|
||||||
|
|
||||||
app_name = 'accounts' # Namensraum zum verhindern von Konflikten zwischen Apps
|
app_name = 'accounts' # Namensraum zum verhindern von Konflikten zwischen Apps
|
||||||
#
|
#
|
||||||
@@ -13,4 +14,22 @@ urlpatterns = [
|
|||||||
path('logout/', LogoutView.as_view(next_page='accounts:login'), name='logout'),
|
path('logout/', LogoutView.as_view(next_page='accounts:login'), name='logout'),
|
||||||
path('login/', LoginView.as_view(template_name='accounts/login.html', next_page='accounts:home'), name='login'),
|
path('login/', LoginView.as_view(template_name='accounts/login.html', next_page='accounts:home'), name='login'),
|
||||||
path('register/', views.register, name='register'),
|
path('register/', views.register, name='register'),
|
||||||
|
path('password_reset/', auth_views.PasswordResetView.as_view(success_url=reverse_lazy('accounts:password_reset_done')), name='password_reset'),
|
||||||
|
path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
|
||||||
|
path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
path('password_change/', views.password_changed, name='password_change'),
|
||||||
|
path('password_change/done/', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
|
||||||
|
path('delete_account/', views.deleteAccount, name="delete_account"),
|
||||||
|
path(
|
||||||
|
'reset/<uidb64>/<token>/',
|
||||||
|
auth_views.PasswordResetConfirmView.as_view(
|
||||||
|
template_name='registration/password_reset_confirm.html',
|
||||||
|
success_url=reverse_lazy('accounts:password_reset_complete')
|
||||||
|
),
|
||||||
|
name='password_reset_confirm'
|
||||||
|
),
|
||||||
|
|
||||||
]
|
]
|
||||||
@@ -2,12 +2,20 @@ from django.shortcuts import render, redirect
|
|||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth import login, authenticate
|
from django.contrib.auth import login, authenticate
|
||||||
from .forms import RegisterForm
|
from .forms import RegisterForm
|
||||||
|
from django.contrib.auth.forms import PasswordChangeForm
|
||||||
|
from django.contrib.auth import update_session_auth_hash
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth import logout
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
@login_required
|
@login_required
|
||||||
def home(request):
|
def home(request):
|
||||||
return render(request, 'accounts/home.html')
|
return render(request, 'accounts/home.html')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def register(response):
|
def register(response):
|
||||||
if response.method == "POST":
|
if response.method == "POST":
|
||||||
form = RegisterForm(response.POST)
|
form = RegisterForm(response.POST)
|
||||||
@@ -19,3 +27,33 @@ def register(response):
|
|||||||
form = RegisterForm()
|
form = RegisterForm()
|
||||||
|
|
||||||
return render(response, "accounts/register.html", {"form":form})
|
return render(response, "accounts/register.html", {"form":form})
|
||||||
|
|
||||||
|
from django.contrib.auth import views as auth_views
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def password_changed(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = PasswordChangeForm(user=request.user, data=request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
user = form.save()
|
||||||
|
#update_session_auth_hash(request, user) #Hier wäre der User nach Passwortänderung noch angemeldet!
|
||||||
|
logout(request)
|
||||||
|
messages.success(request, "Das Passwort wurde erfolgreich geändert!")
|
||||||
|
return redirect('accounts:home')
|
||||||
|
|
||||||
|
else:
|
||||||
|
form = PasswordChangeForm(user=request.user)
|
||||||
|
|
||||||
|
return render(request, 'registration/password_change_form.html', {'form': form})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def deleteAccount(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
user=request.user
|
||||||
|
logout(request)
|
||||||
|
user.delete()
|
||||||
|
messages.success(request, "Der Account wurde erfolgreich gelöscht!")
|
||||||
|
return redirect('homepage:home')
|
||||||
|
return render(request, 'registration/delete_account_confirm.html')
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class ComponentsConfig(AppConfig):
|
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
|
||||||
name = 'components'
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
|
|
||||||
# Create your models here.
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
from django.urls import path # type: ignore
|
|
||||||
from . import views
|
|
||||||
|
|
||||||
|
|
||||||
app_name = 'components' # Namensraum zum verhindern von Konflikten zwischen Apps
|
|
||||||
#
|
|
||||||
# Wichtig: Damit Links funktionieren müssen diese so eingebunden werden: {% url 'accounts:login' %} statt {% url 'login' %}
|
|
||||||
#
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('<int:pk>', views.play, name='play'),
|
|
||||||
path('ranking/<int:pk>', views.show_rank, name='ranking')
|
|
||||||
|
|
||||||
]
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
from django.shortcuts import render
|
|
||||||
|
|
||||||
# Create your views here.
|
|
||||||
def play(request,pk): #
|
|
||||||
return render(request, 'components/answer.html', {"pk": pk}) #
|
|
||||||
|
|
||||||
|
|
||||||
def show_rank(request,pk): #
|
|
||||||
return render(request, 'components/ranking.html', {"pk": pk}) #
|
|
||||||
@@ -16,6 +16,7 @@ from pathlib import Path
|
|||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' #TODO: NUR FÜR ENTWICKLUNG
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
|
||||||
@@ -37,7 +38,6 @@ with open(BASE_DIR / 'config' / 'qivip_config.json') as config_file:
|
|||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
'library.apps.LibraryConfig',
|
'library.apps.LibraryConfig',
|
||||||
'homepage.apps.HomepageConfig',
|
'homepage.apps.HomepageConfig',
|
||||||
'components.apps.ComponentsConfig',
|
|
||||||
'accounts.apps.AccountsConfig',
|
'accounts.apps.AccountsConfig',
|
||||||
'play',
|
'play',
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ urlpatterns = [
|
|||||||
path('', include('homepage.urls')),
|
path('', include('homepage.urls')),
|
||||||
path('play/', include('play.urls')),
|
path('play/', include('play.urls')),
|
||||||
path('library/', include('library.urls')),
|
path('library/', include('library.urls')),
|
||||||
path('components/', include('components.urls'))
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from django import forms
|
|||||||
|
|
||||||
class QuizFilterForm(forms.Form):
|
class QuizFilterForm(forms.Form):
|
||||||
search = forms.CharField(required=False, label="Suche", widget=forms.TextInput(attrs={
|
search = forms.CharField(required=False, label="Suche", widget=forms.TextInput(attrs={
|
||||||
'class': 'flex flex-grow rounded-lg p-2' ,'placeholder': 'Suche ...',
|
'class': 'flex flex-grow rounded-lg p-2' ,'placeholder': 'Suche ...', 'list': 'quiz-names',
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,5 +16,6 @@ urlpatterns = [
|
|||||||
path('question/delete/<int:pk>/', views.delete_question, name='delete_question'),
|
path('question/delete/<int:pk>/', views.delete_question, name='delete_question'),
|
||||||
path('detail/copy/<int:pk>/', views.copy_quiz, name='copy_quiz'),
|
path('detail/copy/<int:pk>/', views.copy_quiz, name='copy_quiz'),
|
||||||
path('favorite_quiz/<int:pk>/', views.favorite_quiz, name='favorite_quiz'),
|
path('favorite_quiz/<int:pk>/', views.favorite_quiz, name='favorite_quiz'),
|
||||||
|
path("quiz-names-json/", views.quiz_names_json, name="quiz_names_json"),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
import uuid
|
import uuid
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
|
||||||
from django.shortcuts import render, redirect, get_object_or_404
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
@@ -16,6 +16,18 @@ from django.db.models import Count
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
# Übersicht aller Quizze
|
# Übersicht aller Quizze
|
||||||
|
|
||||||
|
|
||||||
|
def quiz_names_json(request):
|
||||||
|
form = QuizFilterForm(request.GET)
|
||||||
|
if form.is_valid():
|
||||||
|
search = form.cleaned_data.get('search')
|
||||||
|
names = list(
|
||||||
|
QivipQuiz.objects.all().annotate(max_amout_questions=Count('questions')).filter(max_amout_questions__gte=1, status='öffentlich', name__icontains=search)
|
||||||
|
.values_list('name', flat=True)
|
||||||
|
.distinct()
|
||||||
|
)
|
||||||
|
return JsonResponse(names, safe=False)
|
||||||
|
|
||||||
def overview_quiz(request):
|
def overview_quiz(request):
|
||||||
# Filter
|
# Filter
|
||||||
form = QuizFilterForm(request.GET)
|
form = QuizFilterForm(request.GET)
|
||||||
@@ -85,36 +97,6 @@ def overview_quiz(request):
|
|||||||
except:
|
except:
|
||||||
favorite_quizzes=QivipQuiz.objects.none()
|
favorite_quizzes=QivipQuiz.objects.none()
|
||||||
|
|
||||||
"""
|
|
||||||
if search: # Suche nach Namen
|
|
||||||
filter_other_quizzes = filter_other_quizzes.filter(name__icontains=search)
|
|
||||||
filter_my_quizzes = filter_my_quizzes.filter(name__icontains=search)
|
|
||||||
|
|
||||||
if min_amout_questions:
|
|
||||||
filter_other_quizzes = filter_other_quizzes.filter(max_amout_questions__gte=min_amout_questions)
|
|
||||||
filter_my_quizzes = filter_my_quizzes.filter(max_amout_questions__gte=min_amout_questions) if filter_my_quizzes else QivipQuiz.objects.none()
|
|
||||||
|
|
||||||
if max_amout_questions:
|
|
||||||
filter_other_quizzes = filter_other_quizzes.filter(max_amout_questions__lte=max_amout_questions)
|
|
||||||
try:
|
|
||||||
filter_my_quizzes =filter_my_quizzes.filter(max_amout_questions__lte=max_amout_questions)
|
|
||||||
except:
|
|
||||||
filter_my_quizzes = QivipQuiz.objects.none()
|
|
||||||
|
|
||||||
if username:
|
|
||||||
try:
|
|
||||||
user = User.objects.get(username=username) # Benutzer anhand des Namens holen
|
|
||||||
filter_other_quizzes = filter_other_quizzes.filter(user_id=user.id)
|
|
||||||
filter_my_quizzes = filter_my_quizzes.filter(user_id=user.id) # Nach der user_id filtern
|
|
||||||
except User.DoesNotExist:
|
|
||||||
filter_other_quizzes = QivipQuiz.objects.none() # Falls User nicht existiert, leere Query zurückgeben
|
|
||||||
filter_my_quizzes = QivipQuiz.objects.none()
|
|
||||||
|
|
||||||
try:
|
|
||||||
filter_other_quizzes=filter_other_quizzes.exclude(user_id=request.user)
|
|
||||||
except:
|
|
||||||
filter_other_quizzes=filter_other_quizzes
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# Pagination for my quizzes
|
# Pagination for my quizzes
|
||||||
@@ -173,9 +155,6 @@ def favorite_quiz(request, pk):
|
|||||||
|
|
||||||
if favorite.favorite==True:
|
if favorite.favorite==True:
|
||||||
favorite.favorite_date = timezone.now()
|
favorite.favorite_date = timezone.now()
|
||||||
|
|
||||||
statement="Das Quiz '"+ favorite.quiz.name+ "' wurde erfolgreich zu den Favoriten hinzugefügt!"
|
|
||||||
messages.success(request,statement )
|
|
||||||
favorite.save()
|
favorite.save()
|
||||||
else:
|
else:
|
||||||
favorite.favorite_date = None
|
favorite.favorite_date = None
|
||||||
@@ -185,8 +164,9 @@ def favorite_quiz(request, pk):
|
|||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
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!"
|
||||||
|
messages.success(request,statement )
|
||||||
return redirect(request.META.get('HTTP_REFERER', 'library:overview_quiz'))
|
return redirect(request.META.get('HTTP_REFERER', 'library:overview_quiz'))
|
||||||
|
|
||||||
|
|
||||||
@@ -359,7 +339,7 @@ def new_question(request):
|
|||||||
messages.error(request, 'Quiz nicht gefunden oder keine Berechtigung.')
|
messages.error(request, 'Quiz nicht gefunden oder keine Berechtigung.')
|
||||||
return redirect('library:overview_quiz')
|
return redirect('library:overview_quiz')
|
||||||
|
|
||||||
if question_type not in ['multiple_choice', 'true_false']:
|
if question_type not in ['multiple_choice', 'true_false','input']:
|
||||||
base_url = reverse('library:new_question')
|
base_url = reverse('library:new_question')
|
||||||
return redirect(f'{base_url}?type=multiple_choice&quiz_id={quiz_id}')
|
return redirect(f'{base_url}?type=multiple_choice&quiz_id={quiz_id}')
|
||||||
|
|
||||||
@@ -377,6 +357,17 @@ def new_question(request):
|
|||||||
{'value': 'Falsch', 'is_correct': not correct_answer}
|
{'value': 'Falsch', 'is_correct': not correct_answer}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elif question_type == 'input':
|
||||||
|
correct_answer = request.POST.get('correct_answer')
|
||||||
|
json_data = {
|
||||||
|
'type': question_type,
|
||||||
|
'question': question_text,
|
||||||
|
'options': [
|
||||||
|
{'value': correct_answer, 'is_correct': True}
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
elif question_type == 'multiple_choice':
|
elif question_type == 'multiple_choice':
|
||||||
options = []
|
options = []
|
||||||
i = 1
|
i = 1
|
||||||
@@ -428,6 +419,18 @@ def new_question(request):
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
standard_time_per_question = 30
|
standard_time_per_question = 30
|
||||||
|
|
||||||
|
elif question_type == 'input':
|
||||||
|
question_data = {
|
||||||
|
'type': question_type,
|
||||||
|
'question': '',
|
||||||
|
'options': [
|
||||||
|
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
standard_time_per_question = 30
|
||||||
|
|
||||||
elif question_type == 'multiple_choice':
|
elif question_type == 'multiple_choice':
|
||||||
question_data = {
|
question_data = {
|
||||||
'type': question_type,
|
'type': question_type,
|
||||||
@@ -525,6 +528,17 @@ def edit_question(request, pk):
|
|||||||
{'value': 'Falsch', 'is_correct': not correct_answer}
|
{'value': 'Falsch', 'is_correct': not correct_answer}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
elif question_type == 'input':
|
||||||
|
correct_answer = request.POST.get('correct_answer')
|
||||||
|
json_data = {
|
||||||
|
'type': question_type,
|
||||||
|
'question': question_text,
|
||||||
|
'options': [
|
||||||
|
{'value': correct_answer,'is_correct':True}
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
elif question_type == 'multiple_choice':
|
elif question_type == 'multiple_choice':
|
||||||
options = []
|
options = []
|
||||||
i = 1
|
i = 1
|
||||||
|
|||||||
913
django/package-lock.json
generated
913
django/package-lock.json
generated
@@ -9,26 +9,907 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"swiper": "^11.2.6"
|
"@tailwindcss/cli": "^4.1.5",
|
||||||
|
"tailwindcss": "^4.1.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/swiper": {
|
"node_modules/@parcel/watcher": {
|
||||||
"version": "11.2.6",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
|
||||||
"integrity": "sha512-8aXpYKtjy3DjcbzZfz+/OX/GhcU5h+looA6PbAzHMZT6ESSycSp9nAjPCenczgJyslV+rUGse64LMGpWE3PX9Q==",
|
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
|
||||||
"funding": [
|
"hasInstallScript": true,
|
||||||
{
|
"dependencies": {
|
||||||
"type": "patreon",
|
"detect-libc": "^1.0.3",
|
||||||
"url": "https://www.patreon.com/swiperjs"
|
"is-glob": "^4.0.3",
|
||||||
|
"micromatch": "^4.0.5",
|
||||||
|
"node-addon-api": "^7.0.0"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "open_collective",
|
|
||||||
"url": "http://opencollective.com/swiper"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 4.7.0"
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@parcel/watcher-android-arm64": "2.5.1",
|
||||||
|
"@parcel/watcher-darwin-arm64": "2.5.1",
|
||||||
|
"@parcel/watcher-darwin-x64": "2.5.1",
|
||||||
|
"@parcel/watcher-freebsd-x64": "2.5.1",
|
||||||
|
"@parcel/watcher-linux-arm-glibc": "2.5.1",
|
||||||
|
"@parcel/watcher-linux-arm-musl": "2.5.1",
|
||||||
|
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
|
||||||
|
"@parcel/watcher-linux-arm64-musl": "2.5.1",
|
||||||
|
"@parcel/watcher-linux-x64-glibc": "2.5.1",
|
||||||
|
"@parcel/watcher-linux-x64-musl": "2.5.1",
|
||||||
|
"@parcel/watcher-win32-arm64": "2.5.1",
|
||||||
|
"@parcel/watcher-win32-ia32": "2.5.1",
|
||||||
|
"@parcel/watcher-win32-x64": "2.5.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-android-arm64": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-darwin-arm64": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-darwin-x64": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-freebsd-x64": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-linux-arm-glibc": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-linux-arm-musl": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-linux-arm64-glibc": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-linux-arm64-musl": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-linux-x64-glibc": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-linux-x64-musl": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-win32-arm64": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-win32-ia32": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-win32-x64": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/cli": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-Kr567rDwDjY1VUnfqh5/+DCpRf4B8lPs5O9flP4kri7n4AM2aubrIxGSh5GN8s+awUKw/U4+6kNlEnZbBNfUeg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@parcel/watcher": "^2.5.1",
|
||||||
|
"@tailwindcss/node": "4.1.5",
|
||||||
|
"@tailwindcss/oxide": "4.1.5",
|
||||||
|
"enhanced-resolve": "^5.18.1",
|
||||||
|
"mri": "^1.2.0",
|
||||||
|
"picocolors": "^1.1.1",
|
||||||
|
"tailwindcss": "4.1.5"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"tailwindcss": "dist/index.mjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/node": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-CBhSWo0vLnWhXIvpD0qsPephiaUYfHUX3U9anwDaHZAeuGpTiB3XmsxPAN6qX7bFhipyGBqOa1QYQVVhkOUGxg==",
|
||||||
|
"dependencies": {
|
||||||
|
"enhanced-resolve": "^5.18.1",
|
||||||
|
"jiti": "^2.4.2",
|
||||||
|
"lightningcss": "1.29.2",
|
||||||
|
"tailwindcss": "4.1.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-1n4br1znquEvyW/QuqMKQZlBen+jxAbvyduU87RS8R3tUSvByAkcaMTkJepNIrTlYhD+U25K4iiCIxE6BGdRYA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@tailwindcss/oxide-android-arm64": "4.1.5",
|
||||||
|
"@tailwindcss/oxide-darwin-arm64": "4.1.5",
|
||||||
|
"@tailwindcss/oxide-darwin-x64": "4.1.5",
|
||||||
|
"@tailwindcss/oxide-freebsd-x64": "4.1.5",
|
||||||
|
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.5",
|
||||||
|
"@tailwindcss/oxide-linux-arm64-gnu": "4.1.5",
|
||||||
|
"@tailwindcss/oxide-linux-arm64-musl": "4.1.5",
|
||||||
|
"@tailwindcss/oxide-linux-x64-gnu": "4.1.5",
|
||||||
|
"@tailwindcss/oxide-linux-x64-musl": "4.1.5",
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi": "4.1.5",
|
||||||
|
"@tailwindcss/oxide-win32-arm64-msvc": "4.1.5",
|
||||||
|
"@tailwindcss/oxide-win32-x64-msvc": "4.1.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-android-arm64": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-LVvM0GirXHED02j7hSECm8l9GGJ1RfgpWCW+DRn5TvSaxVsv28gRtoL4aWKGnXqwvI3zu1GABeDNDVZeDPOQrw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-darwin-arm64": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-//TfCA3pNrgnw4rRJOqavW7XUk8gsg9ddi8cwcsWXp99tzdBAZW0WXrD8wDyNbqjW316Pk2hiN/NJx/KWHl8oA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-darwin-x64": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-XQorp3Q6/WzRd9OalgHgaqgEbjP3qjHrlSUb5k1EuS1Z9NE9+BbzSORraO+ecW432cbCN7RVGGL/lSnHxcd+7Q==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-freebsd-x64": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-bPrLWbxo8gAo97ZmrCbOdtlz/Dkuy8NK97aFbVpkJ2nJ2Jo/rsCbu0TlGx8joCuA3q6vMWTSn01JY46iwG+clg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-1gtQJY9JzMAhgAfvd/ZaVOjh/Ju/nCoAsvOVJenWZfs05wb8zq+GOTnZALWGqKIYEtyNpCzvMk+ocGpxwdvaVg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-dtlaHU2v7MtdxBXoqhxwsWjav7oim7Whc6S9wq/i/uUMTWAzq/gijq1InSgn2yTnh43kR+SFvcSyEF0GCNu1PQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-fg0F6nAeYcJ3CriqDT1iVrqALMwD37+sLzXs8Rjy8Z1ZHshJoYceodfyUwGJEsQoTyWbliFNRs2wMQNXtT7MVA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-SO+F2YEIAHa1AITwc8oPwMOWhgorPzzcbhWEb+4oLi953h45FklDmM8dPSZ7hNHpIk9p/SCZKUYn35t5fjGtHA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-6UbBBplywkk/R+PqqioskUeXfKcBht3KU7juTi1UszJLx0KPXUo10v2Ok04iBJIaDPkIFkUOVboXms5Yxvaz+g==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-hwALf2K9FHuiXTPqmo1KeOb83fTRNbe9r/Ixv9ZNQ/R24yw8Ge1HOWDDgTdtzntIaIUJG5dfXCf4g9AD4RiyhQ==",
|
||||||
|
"bundleDependencies": [
|
||||||
|
"@napi-rs/wasm-runtime",
|
||||||
|
"@emnapi/core",
|
||||||
|
"@emnapi/runtime",
|
||||||
|
"@tybys/wasm-util",
|
||||||
|
"@emnapi/wasi-threads",
|
||||||
|
"tslib"
|
||||||
|
],
|
||||||
|
"cpu": [
|
||||||
|
"wasm32"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emnapi/core": "^1.4.3",
|
||||||
|
"@emnapi/runtime": "^1.4.3",
|
||||||
|
"@emnapi/wasi-threads": "^1.0.2",
|
||||||
|
"@napi-rs/wasm-runtime": "^0.2.9",
|
||||||
|
"@tybys/wasm-util": "^0.9.0",
|
||||||
|
"tslib": "^2.8.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-oDKncffWzaovJbkuR7/OTNFRJQVdiw/n8HnzaCItrNQUeQgjy7oUiYpsm9HUBgpmvmDpSSbGaCa2Evzvk3eFmA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-WiR4dtyrFdbb+ov0LK+7XsFOsG+0xs0PKZKkt41KDn9jYpO7baE3bXiudPVkTqUEwNfiglCygQHl2jklvSBi7Q==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/braces": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||||
|
"dependencies": {
|
||||||
|
"fill-range": "^7.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/detect-libc": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
|
||||||
|
"bin": {
|
||||||
|
"detect-libc": "bin/detect-libc.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/enhanced-resolve": {
|
||||||
|
"version": "5.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
|
||||||
|
"integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==",
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": "^4.2.4",
|
||||||
|
"tapable": "^2.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.13.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fill-range": {
|
||||||
|
"version": "7.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
|
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||||
|
"dependencies": {
|
||||||
|
"to-regex-range": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/graceful-fs": {
|
||||||
|
"version": "4.2.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||||
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
||||||
|
},
|
||||||
|
"node_modules/is-extglob": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-glob": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||||
|
"dependencies": {
|
||||||
|
"is-extglob": "^2.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-number": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jiti": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
|
||||||
|
"bin": {
|
||||||
|
"jiti": "lib/jiti-cli.mjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss": {
|
||||||
|
"version": "1.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz",
|
||||||
|
"integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==",
|
||||||
|
"dependencies": {
|
||||||
|
"detect-libc": "^2.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"lightningcss-darwin-arm64": "1.29.2",
|
||||||
|
"lightningcss-darwin-x64": "1.29.2",
|
||||||
|
"lightningcss-freebsd-x64": "1.29.2",
|
||||||
|
"lightningcss-linux-arm-gnueabihf": "1.29.2",
|
||||||
|
"lightningcss-linux-arm64-gnu": "1.29.2",
|
||||||
|
"lightningcss-linux-arm64-musl": "1.29.2",
|
||||||
|
"lightningcss-linux-x64-gnu": "1.29.2",
|
||||||
|
"lightningcss-linux-x64-musl": "1.29.2",
|
||||||
|
"lightningcss-win32-arm64-msvc": "1.29.2",
|
||||||
|
"lightningcss-win32-x64-msvc": "1.29.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-darwin-arm64": {
|
||||||
|
"version": "1.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz",
|
||||||
|
"integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-darwin-x64": {
|
||||||
|
"version": "1.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz",
|
||||||
|
"integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-freebsd-x64": {
|
||||||
|
"version": "1.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz",
|
||||||
|
"integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-linux-arm-gnueabihf": {
|
||||||
|
"version": "1.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz",
|
||||||
|
"integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-linux-arm64-gnu": {
|
||||||
|
"version": "1.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz",
|
||||||
|
"integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-linux-arm64-musl": {
|
||||||
|
"version": "1.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz",
|
||||||
|
"integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-linux-x64-gnu": {
|
||||||
|
"version": "1.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz",
|
||||||
|
"integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-linux-x64-musl": {
|
||||||
|
"version": "1.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz",
|
||||||
|
"integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-win32-arm64-msvc": {
|
||||||
|
"version": "1.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz",
|
||||||
|
"integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss-win32-x64-msvc": {
|
||||||
|
"version": "1.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz",
|
||||||
|
"integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lightningcss/node_modules/detect-libc": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/micromatch": {
|
||||||
|
"version": "4.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||||
|
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||||
|
"dependencies": {
|
||||||
|
"braces": "^3.0.3",
|
||||||
|
"picomatch": "^2.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mri": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-addon-api": {
|
||||||
|
"version": "7.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||||
|
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="
|
||||||
|
},
|
||||||
|
"node_modules/picocolors": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
|
||||||
|
},
|
||||||
|
"node_modules/picomatch": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tailwindcss": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-nYtSPfWGDiWgCkwQG/m+aX83XCwf62sBgg3bIlNiiOcggnS1x3uVRDAuyelBFL+vJdOPPCGElxv9DjHJjRHiVA=="
|
||||||
|
},
|
||||||
|
"node_modules/tapable": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/to-regex-range": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"is-number": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"swiper": "^11.2.6"
|
"@tailwindcss/cli": "^4.1.5",
|
||||||
|
"tailwindcss": "^4.1.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,10 @@ class GameConsumer(AsyncWebsocketConsumer):
|
|||||||
|
|
||||||
elif message_type == 'submit_answer':
|
elif message_type == 'submit_answer':
|
||||||
participant_id = text_data_json['participant_id']
|
participant_id = text_data_json['participant_id']
|
||||||
|
try:
|
||||||
answer = text_data_json['answer']
|
answer = text_data_json['answer']
|
||||||
|
except:
|
||||||
|
answer=-1
|
||||||
time_remaining = text_data_json.get('time_remaining', 0)
|
time_remaining = text_data_json.get('time_remaining', 0)
|
||||||
|
|
||||||
# Save answer and update participant score
|
# Save answer and update participant score
|
||||||
@@ -182,15 +185,33 @@ class GameConsumer(AsyncWebsocketConsumer):
|
|||||||
|
|
||||||
# Check if answer is correct
|
# Check if answer is correct
|
||||||
is_correct = False
|
is_correct = False
|
||||||
if answer_index >= 0: # -1 means timeout
|
|
||||||
question_data = json.loads(current_question.data)
|
question_data = json.loads(current_question.data)
|
||||||
|
print(answer_index)
|
||||||
|
try:
|
||||||
|
if answer_index >= 0 : # -1 means timeout
|
||||||
is_correct = question_data['options'][answer_index]['is_correct']
|
is_correct = question_data['options'][answer_index]['is_correct']
|
||||||
|
print(is_correct)
|
||||||
|
except:
|
||||||
|
user_input = str(answer_index).strip().lower().replace(" ", "")
|
||||||
|
correct_value = str(question_data['options'][0].get('value', '')).strip().lower().replace(" ", "")
|
||||||
|
print("Richtig",correct_value)
|
||||||
|
print(user_input)
|
||||||
|
if user_input == correct_value:
|
||||||
|
is_correct=True
|
||||||
|
answer_index=int(0)
|
||||||
|
print(is_correct)
|
||||||
|
else:
|
||||||
|
answer_index=int(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Calculate score based on correctness and time
|
# Calculate score based on correctness and time
|
||||||
score = 0
|
score = 0
|
||||||
if is_correct:
|
if is_correct:
|
||||||
base_score = 1000
|
base_score = 1000
|
||||||
time_factor = time_remaining / 30000 # 30 seconds max
|
time_factor = time_remaining / int(current_question.time_per_question)/int(1000)
|
||||||
score = int(base_score * (0.5 + 0.5 * time_factor))
|
score = int(base_score * (0.5 + 0.5 * time_factor))
|
||||||
|
|
||||||
# Update or create answer in QuizAnswer table
|
# Update or create answer in QuizAnswer table
|
||||||
|
|||||||
13
django/static/swiper/swiper-bundle.min.css
vendored
13
django/static/swiper/swiper-bundle.min.css
vendored
File diff suppressed because one or more lines are too long
14
django/static/swiper/swiper-bundle.min.js
vendored
14
django/static/swiper/swiper-bundle.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -9,11 +9,15 @@
|
|||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
|
|
||||||
<form action="{% url 'accounts:logout' %}" method="post">
|
<form action="{% url 'accounts:logout' %}" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<button class="bg-blue-600 text-white p-3 rounded-full font-black" type="submit">Abmelden</button>
|
<button class="w-full p-3 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200 cursor-pointer" type="submit">Abmelden</button>
|
||||||
</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-red-600"><a href="{% url 'accounts:delete_account' %}">Account löschen</a></button>
|
||||||
</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">qivip
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -24,9 +24,10 @@
|
|||||||
<div class="items-center w-full">
|
<div class="items-center w-full">
|
||||||
<input class=" w-full p-3 rounded-full bg-gray-200 focus:scale-105 transition duration-200 font-black" type="password" name="password" id="password" required placeholder="PASSWORT">
|
<input class=" w-full p-3 rounded-full bg-gray-200 focus:scale-105 transition duration-200 font-black" type="password" name="password" id="password" required placeholder="PASSWORT">
|
||||||
</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" class="login-button">Anmelden</button>
|
<button class="w-full p-3 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200 cursor-pointer" type="submit" class="login-button">Anmelden</button>
|
||||||
</form>
|
</form>
|
||||||
<button class="text-center text-sm w-full mt-2 font-light text-blue-600"><a href="{% url 'accounts:register' %}" class="register_link">Noch kein Konto?</a></button>
|
<button class="text-center text-sm w-full mt-2 font-light text-blue-600"><a href="{% url 'accounts:register' %}" class="register_link">Noch kein Konto?</a></button>
|
||||||
|
<button class="text-center text-sm w-full mt-2 font-light text-blue-600"><a href="{% url 'accounts:password_reset' %}" class="register_link">Passwort vergessen?</a></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -37,7 +37,14 @@
|
|||||||
{{ form.password2 }}
|
{{ form.password2 }}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="register">
|
||||||
|
|
||||||
|
{{ form.email }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="text-center text-gray-600 text-sm dislay-flex align-bottom">
|
||||||
|
<label class=''>Mit der Erstellung ihres Kontos stimmen Sie der <a class="text-blue-600" href="/privacy">Datenschutzerklärung </a> zu.</label>
|
||||||
|
</div>
|
||||||
<button class="w-full p-3 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200" type="submit" class="login-button">Registrieren</button>
|
<button class="w-full p-3 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200" type="submit" class="login-button">Registrieren</button>
|
||||||
</form>
|
</form>
|
||||||
<button class="text-center text-sm w-full mt-2 font-light text-blue-600"><a href="{% url 'accounts:login' %}" class="register_link">Bereits ein Konto?</a></button>
|
<button class="text-center text-sm w-full mt-2 font-light text-blue-600"><a href="{% url 'accounts:login' %}" class="register_link">Bereits ein Konto?</a></button>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<body>
|
<body>
|
||||||
{% include 'partials/_nav.html' %}
|
{% include 'partials/_nav.html' %}
|
||||||
{% block content%}{% endblock %}
|
{% block content%}{% endblock %}
|
||||||
|
{% block faqs%}{% endblock %}
|
||||||
{% include 'partials/_footer.html' %}
|
{% include 'partials/_footer.html' %}
|
||||||
|
|
||||||
<!-- Toast Container -->
|
<!-- Toast Container -->
|
||||||
@@ -71,5 +72,8 @@
|
|||||||
localStorage.setItem("meine_seite_scroll", 0);}
|
localStorage.setItem("meine_seite_scroll", 0);}
|
||||||
</script>
|
</script>
|
||||||
{% block extra_js %}{% endblock %}
|
{% block extra_js %}{% endblock %}
|
||||||
|
<style>html {
|
||||||
|
overflow-y: scroll;
|
||||||
|
}</style>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{% extends 'components/base.html' %}
|
|
||||||
{% load static %}
|
|
||||||
{% block title %}Antwort{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
<link rel="stylesheet" href="{% static 'css/t-style.css' %}">
|
|
||||||
|
|
||||||
<!-- TODO Bedingung festlegen: Quiztyp unterscheiden % if <Bedingung> % -->
|
|
||||||
{% if user.is_authenticated %}
|
|
||||||
<button class="overflow-x-auto text-[clamp(0.3rem,5vw,1rem)] break-words border-4 border-gray-500 text-2xl font-black m-0.75 bg-red-500 rounded-sm shadow-[0_2px_2px_rgba(0,0,0,0.1)] text-center text-white">1</button>
|
|
||||||
<button class="overflow-x-auto text-[clamp(0.3rem,5vw,1rem)] break-words border-4 border-gray-500 text-2xl font-black m-0.75 bg-indigo-500 rounded-sm shadow-[0_2px_2px_rgba(0,0,0,0.1)] text-center text-white">2</button>
|
|
||||||
<button class="overflow-x-auto text-[clamp(0.3rem,5vw,1rem)] break-words border-4 border-gray-500 text-2xl font-black m-0.75 bg-yellow-500 rounded-sm shadow-[0_2px_2px_rgba(0,0,0,0.1)] text-center text-white">3</button>
|
|
||||||
<button class="overflow-x-auto text-[clamp(0.3rem,5vw,1rem)] break-words border-4 border-gray-500 text-2xl font-black m-0.75 bg-green-500 rounded-sm shadow-[0_2px_2px_rgba(0,0,0,0.1)] text-center text-white">4</button>
|
|
||||||
|
|
||||||
<!-- TODO wieder einfügen, wenn Bedingung gestetzt -->
|
|
||||||
{% else %}
|
|
||||||
<button class=" overflow-x-auto text-[clamp(0.3rem,5vw,1rem)] break-words border-4 border-gray-500 text-2xl font-black m-0.75 bg-green-500 rounded-sm shadow-[0_2px_2px_rgba(0,0,0,0.1)] text-center text-white">wahr</button>
|
|
||||||
<button class=" overflow-x-auto text-[clamp(0.3rem,5vw,1rem)] break-words border-4 border-gray-500 text-2xl font-black m-0.75 bg-red-500 rounded-sm shadow-[0_2px_2px_rgba(0,0,0,0.1)] text-center text-white">falsch</button>
|
|
||||||
|
|
||||||
|
|
||||||
<!--TODO wieder einfügen, wenn Bedingung gestetzt plus -->
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!doctype html>
|
|
||||||
<html class="h-full">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
</head>
|
|
||||||
<body class="dark:bg-gray-900 h-full m-0">
|
|
||||||
|
|
||||||
<div style="height: calc(12vh);" class=" m-0 text-white bg-blue-600 rounded-lg h-12 shadow-md font-semibold px-1 w-full h-20 shadow-[0_2px_2px_rgba(0,0,0,0.1)] break-words text-center flex items-center justify-center overflow-x-auto text-[clamp(0.55rem,5vw,1.5rem)]" > Frage: Wie hoch ist der Eiffelturm insgesamt?
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" dark:bg-gray-900 flex justify-end gap-2 " style="height: calc(12vh);">
|
|
||||||
<span class="mt-4 text-[clamp(0.6rem,5vw,1rem)] overflow-x-auto ml-0.75 text-white bg-blue-400 mb-6 h-12 rounded-sm p-3 shadow-[0_2px_2px_rgba(0,0,0,0.1)] z-40 items-center">Zeit: 60s</span>
|
|
||||||
<div class="mt-4 text-[clamp(0.6rem,5vw,1rem)] overflow-x-auto mr-0.75 bg-gray-500 text-white h-12 mb-6 rounded-sm p-3 shadow-[0_2px_2px_rgba(0,0,0,0.1)] z-40 items-center ">Deine Punkte: 60</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="mt-3 flex justify-center -z-1 " style="height: calc(37vh);"> <img class="object-cover " src="{% static 'components/Ausgabe.png' %}" alt="Bild"> </div>
|
|
||||||
<div class="w-full grid grid-cols-2 p-2 h-full" style="height: calc(38vh);min-height: 50px;">
|
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="absolute bottom-0 right-0">
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<link rel="stylesheet" href="{% static 'css/t-style.css' %}">
|
|
||||||
<!doctype html>
|
|
||||||
<html class="h-full">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
</head>
|
|
||||||
<body class=" dark:bg-gray-900 w-full justify-center h-full m-0">
|
|
||||||
<div style="height: calc(10vh);" class=" m-0 text-white bg-blue-600 rounded-lg h-12 shadow-md font-semibold px-1 w-full h-20 shadow-[0_2px_2px_rgba(0,0,0,0.1)] break-words text-center flex items-center justify-center overflow-x-auto text-[clamp(0.75rem,5vw,1.5rem)]" >Ranking
|
|
||||||
</div>
|
|
||||||
<div class="m-4 flex justify-end font-bold">Frage 1/10</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="text-[clamp(0.75rem,5vw,1.25rem)] font-bold flex items-center justify-around border-blue-600 border-4 space-x-2 mt-2 overflow-x-auto rounded-lg p-4 shadow-[0_2px_2px_rgba(0,0,0,0.1)] w-full">
|
|
||||||
<div style="background:linear-gradient(120deg, rgb(255, 208, 0),rgb(216, 151, 21))" class="text-white !important px-4 rounded-sm">1. Platz</div>
|
|
||||||
<div class="text-stone-900 ">6000 Punkte</div>
|
|
||||||
<div class="">Person XY</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" text-[clamp(0.75rem,5vw,1.25rem)] font-bold p-4 flex items-center justify-around border-blue-600 border-4 space-x-2 mt-2 overflow-x-auto rounded-lg shadow-[0_2px_2px_rgba(0,0,0,0.1)] w-full">
|
|
||||||
<div style="background:linear-gradient(120deg, rgb(102, 122, 122),rgb(194, 186, 186))" class="text-white !important px-4 rounded-sm">2. Platz</div>
|
|
||||||
<div class="text-stone-900 ">5000 Punkte</div>
|
|
||||||
<div class="">Person XY</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" text-[clamp(0.75rem,5vw,1.25rem)] font-bold flex items-center justify-around border-blue-600 border-4 space-x-2 mt-2 overflow-x-auto rounded-lg p-4 shadow-[0_2px_2px_rgba(0,0,0,0.1)] w-full">
|
|
||||||
<div style="background:linear-gradient(120deg, rgb(211, 91, 17),rgb(219, 168, 109))" class="text-white !important px-4 rounded-sm">3. Platz</div>
|
|
||||||
<div class="text-stone-900 ">600 Punkte</div>
|
|
||||||
<div class="">Person XY</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" text-[clamp(0.75rem,5vw,1.25rem)] items-center flex justify-around font-bold border-blue-600 border-4 space-x-2 mt-2 text-[clamp(0.6rem,5vw,1rem)] overflow-x-auto rounded-lg p-4 shadow-[0_2px_2px_rgba(0,0,0,0.1)] w-full">
|
|
||||||
<div>4. Platz</div>
|
|
||||||
<div>200 Punkte</div>
|
|
||||||
<div>Person XY</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="absolute bottom-0 right-0">
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<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-2xl text-md">Interaktives Lernen neu definiert.</h3>
|
<h3 class="mt-4 italic font-extralight sm:text-4xl text-md">forever and forall</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">
|
||||||
<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>
|
||||||
@@ -13,3 +13,155 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block faqs %}
|
||||||
|
<style>
|
||||||
|
details[open] summary svg {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<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 class="text-2xl font-bold text-gray-900">FAQs</h2>
|
||||||
|
<div class="h-0.5 flex-grow bg-gradient-to-r from-blue-600 to-transparent rounded-full"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="input-group !max-w-4xl tracking-wide">
|
||||||
|
<h1 class="font-black text-blue-600 flex justify-between gap-2 lg:text-lg">
|
||||||
|
|
||||||
|
|
||||||
|
FAQs - häufig gestellte Fragen
|
||||||
|
<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="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 5.25h.008v.008H12v-.008Z" />
|
||||||
|
</svg></h1>
|
||||||
|
|
||||||
|
</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">Was ist 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">qivip ist eine Webseite zum Lernen! Es können vor allem Quizze erstellt, bearbeitet, kopiert und auch gespielt werden. </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">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 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 %}
|
||||||
@@ -90,6 +90,14 @@
|
|||||||
<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</h2>
|
||||||
<div class="flex space-x-2 flex-wrap">
|
<div class="flex space-x-2 flex-wrap">
|
||||||
|
{% if quiz.user_id == request.user %}
|
||||||
|
<a href="{% url 'library:new_question' %}?type=input&quiz_id={{ quiz.id }}"
|
||||||
|
class=" mt-1 bg-green-100 text-green-800 px-4 py-2 rounded-md text-xs lg:text-lg hover:border-blue-600 border-2">
|
||||||
|
Eingabe
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{% if quiz.user_id == request.user %}
|
{% if quiz.user_id == request.user %}
|
||||||
<a href="{% url 'library:new_question' %}?type=multiple_choice&quiz_id={{ quiz.id }}"
|
<a href="{% url 'library:new_question' %}?type=multiple_choice&quiz_id={{ quiz.id }}"
|
||||||
class=" mt-1 bg-blue-100 text-blue-800 px-4 py-2 rounded-md text-xs lg:text-lg hover:border-blue-600 border-2">
|
class=" mt-1 bg-blue-100 text-blue-800 px-4 py-2 rounded-md text-xs lg:text-lg hover:border-blue-600 border-2">
|
||||||
@@ -118,8 +126,8 @@
|
|||||||
<div class="flex-grow">
|
<div class="flex-grow">
|
||||||
<p class="font-medium">{{ question.data.question }}</p>
|
<p class="font-medium">{{ question.data.question }}</p>
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium {% if question.data.type == 'multiple_choice' %}bg-blue-100 text-blue-800{% else %}bg-purple-100 text-purple-800{% endif %}">
|
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium {% if question.data.type == 'multiple_choice' %}bg-blue-100 text-blue-800 {% elif question.data.type == 'input' %} bg-green-100 text-green-800 {% else %}bg-purple-100 text-purple-800{% endif %}">
|
||||||
{% if question.data.type == 'multiple_choice' %}Multiple Choice{% else %}Wahr/Falsch{% endif %}
|
{% if question.data.type == 'multiple_choice' %}Multiple Choice{% elif question.data.type == 'input' %}Eingabe{% else %}Wahr/Falsch{% endif %}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
@@ -143,6 +151,18 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
{% elif question.data.type == 'input' %}
|
||||||
|
<ul class="space-y-1 ">
|
||||||
|
{% for option in question.data.options %}
|
||||||
|
<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">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
||||||
|
</svg>
|
||||||
|
<span class="font-medium text-green-700">{{ option.value }}</span>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{% for option in question.data.options %}
|
{% for option in question.data.options %}
|
||||||
{% if option.is_correct %}
|
{% if option.is_correct %}
|
||||||
@@ -217,4 +237,5 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -18,7 +18,9 @@
|
|||||||
<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="bg-blue-200 p-2 m-2 rounded-lg border-2 border-blue-400" type="file" name="quiz_image" id="quiz_image">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center text-gray-600 text-sm dislay-flex align-bottom">
|
||||||
|
<label class=''>Mit der Erstellung von diesem Quiz stimmen Sie der <a class="text-blue-600" href="/privacy">Datenschutzerklärung </a> zu.</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-center space-x-3">
|
<div class="flex justify-center space-x-3">
|
||||||
<a href="{% if object.quiz_id %}{% url 'library:detail_quiz' object.quiz_id.id %}{% else %}{% url 'library:overview_quiz' %}{% endif %}"
|
<a href="{% if object.quiz_id %}{% url 'library:detail_quiz' object.quiz_id.id %}{% else %}{% url 'library:overview_quiz' %}{% endif %}"
|
||||||
|
|||||||
@@ -2,21 +2,8 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block extra_css %}
|
{% block extra_css %}
|
||||||
<link rel="stylesheet" href="{% static 'swiper/swiper-bundle.min.css' %}">
|
|
||||||
<style>
|
<style>
|
||||||
.swiper {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.swiper-slide {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 18px;
|
|
||||||
background: #fff;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-outline {
|
.custom-outline {
|
||||||
-webkit-text-stroke: 0.2px rgb(0, 0, 0);
|
-webkit-text-stroke: 0.2px rgb(0, 0, 0);
|
||||||
|
|||||||
93
django/templates/library/question/question_input.html
Normal file
93
django/templates/library/question/question_input.html
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mx-auto px-4">
|
||||||
|
<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>
|
||||||
|
<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">
|
||||||
|
Zurück zum Quiz
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white rounded-lg shadow-md p-6 border-blue-600 border-2 rounded-xl shadow-md">
|
||||||
|
<form method="post" class="space-y-6" enctype="multipart/form-data">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<!-- Question Text -->
|
||||||
|
<div>
|
||||||
|
<label for="question" class="block text-sm font-medium text-gray-700">Frage</label>
|
||||||
|
<div class="mt-1">
|
||||||
|
<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"
|
||||||
|
required>{{ question.data.question }}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if image %}
|
||||||
|
<img src="{{ image.image.url }}" style="max-width: 500px;" alt="Bild der Frage">
|
||||||
|
<label for="reset_image">
|
||||||
|
<input type="checkbox" name="reset_ques_image" id="reset_ques_image">
|
||||||
|
Bild zurücksetzen
|
||||||
|
</label>
|
||||||
|
{% endif %}
|
||||||
|
<div>
|
||||||
|
<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">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Eingabe -->
|
||||||
|
{% if question and question.data.options %}
|
||||||
|
{% for option in question.data.options %}
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Richtige Antwort</label>
|
||||||
|
<div class="flex space-x-4">
|
||||||
|
<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"
|
||||||
|
required>{{ option.value }}</textarea>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Richtige Antwort</label>
|
||||||
|
<div class="flex space-x-4">
|
||||||
|
<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"
|
||||||
|
required></textarea>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="p-4">
|
||||||
|
<label class="font-bold" for="time_per_question">Zeit pro Frage:</label>
|
||||||
|
<select name="time_per_question" id="time_per_question">
|
||||||
|
<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="30" {% if standard_time_per_question == "30" or time_per_question == "30" %}selected{% endif %}>30 Sekunden</option>
|
||||||
|
<option value="45" {% if standard_time_per_question == "45" or time_per_question == "45" %}selected{% endif %}>45 Sekunden</option>
|
||||||
|
<option value="60" {% if standard_time_per_question == "60" or time_per_question == "60" %}selected{% endif %}>1 Minute</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>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end space-x-3">
|
||||||
|
<a href="{% url 'library:detail_quiz' quiz.id %}"
|
||||||
|
class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
||||||
|
Abbrechen
|
||||||
|
</a>
|
||||||
|
<button type="submit"
|
||||||
|
class="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
||||||
|
{% if question %}Speichern{% else %}Erstellen{% endif %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<!-- 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 '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">
|
||||||
<input 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">
|
||||||
<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">
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Desktop Navigation Links - Hidden on mobile -->
|
<!-- Desktop Navigation Links - Hidden on mobile -->
|
||||||
<div class="hidden md:flex items-center space-x-4 md:w-40">
|
<div class="hidden md:flex items-center">
|
||||||
<ul class="flex space-x-4 qp-nav-list">
|
<ul class="flex space-x-4 qp-nav-list">
|
||||||
{% if show_search %}
|
{% if show_search %}
|
||||||
<li><a href="{% url 'library:overview_quiz' %}">Bibliothek</a></li>
|
<li><a href="{% url 'library:overview_quiz' %}">Bibliothek</a></li>
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
<!-- 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 '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">
|
||||||
<input 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">
|
||||||
<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"
|
||||||
@@ -63,6 +63,78 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<datalist id="quiz-names-desktop">
|
||||||
|
{% for quiz in quiz_names %}
|
||||||
|
<option value="{{ quiz.name }}">
|
||||||
|
{% endfor %}
|
||||||
|
</datalist>
|
||||||
|
|
||||||
|
<datalist id="quiz-names-mobile">
|
||||||
|
{% for quiz in quiz_names %}
|
||||||
|
<button value="{{ quiz.name }}" onclick="performSearch(this.value)"><option value="{{ quiz.name }}" ></option></button>
|
||||||
|
{% endfor %}
|
||||||
|
</datalist>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{{ quiz_names|json_script:"quiz-names-data" }}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async function fetchQuizNames() {
|
||||||
|
try {
|
||||||
|
const response = await fetch("{% url 'library:quiz_names_json' %}");
|
||||||
|
if (!response.ok) throw new Error("Netzwerkfehler");
|
||||||
|
const data = await response.json();
|
||||||
|
if (Array.isArray(data)) return data;
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Fehler beim Laden der Quiz-Namen:", err);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupAutocomplete(inputId, datalistId, quizNames) {
|
||||||
|
const searchInput = document.getElementById(inputId);
|
||||||
|
const datalist = document.getElementById(datalistId);
|
||||||
|
if (!searchInput || !datalist) return;
|
||||||
|
|
||||||
|
// Wenn der Benutzer den Text ändert, Filter anwenden
|
||||||
|
searchInput.addEventListener('input', () => {
|
||||||
|
const value = searchInput.value.toLowerCase();
|
||||||
|
datalist.innerHTML = '';
|
||||||
|
quizNames
|
||||||
|
.filter(name => name.toLowerCase().includes(value))
|
||||||
|
.slice(0, 10)
|
||||||
|
.forEach(name => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = name;
|
||||||
|
datalist.appendChild(option);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Funktion zum Durchführen der Suche
|
||||||
|
function performSearch(query) {
|
||||||
|
datalist.innerHTML = '';
|
||||||
|
// Hier kann deine Logik zur Verarbeitung der Suche eingefügt werden
|
||||||
|
|
||||||
|
// Falls du die Seite zu einer Suchergebnisseite weiterleiten möchtest:
|
||||||
|
window.location.href = `{% url 'library:overview_quiz' %}?search=${query}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
const quizNames = await fetchQuizNames();
|
||||||
|
setupAutocomplete('quiz-search-desktop', 'quiz-names-desktop', quizNames);
|
||||||
|
setupAutocomplete('quiz-search-mobile', 'quiz-names-mobile', quizNames);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- Mobile Navigation Links -->
|
<!-- Mobile Navigation Links -->
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<p id="answer-count" class="text-6xl font-bold text-blue-700">0/0</p>
|
<p id="answer-count" class="text-6xl font-bold text-blue-700">0/0</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% 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
|
||||||
@@ -48,7 +48,21 @@
|
|||||||
</button>
|
</button>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{% if request.session.mode == "learn" %}
|
||||||
|
<form action="">
|
||||||
|
<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 ">
|
||||||
|
|
||||||
|
<button {% if request.session.mode == "learn" %}
|
||||||
|
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">
|
||||||
|
abschicken
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -155,7 +169,9 @@
|
|||||||
gameSocket.send(JSON.stringify({
|
gameSocket.send(JSON.stringify({
|
||||||
'type': 'update_participants'
|
'type': 'update_participants'
|
||||||
}));
|
}));
|
||||||
|
{% if request.session.mode != "learn" %}
|
||||||
updateTimer();
|
updateTimer();
|
||||||
|
{% endif %}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -177,10 +193,20 @@
|
|||||||
|
|
||||||
function submitAnswer(optionIndex) {
|
function submitAnswer(optionIndex) {
|
||||||
if (hasAnswered) return;
|
if (hasAnswered) return;
|
||||||
|
let input = ""; // Declare input here
|
||||||
|
|
||||||
|
try {
|
||||||
|
input = document.getElementById("textanswer").value;
|
||||||
|
} catch (e) {
|
||||||
|
input = "";
|
||||||
|
}
|
||||||
hasAnswered = true;
|
hasAnswered = true;
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const timeRemaining = Math.max(0, questionDuration - (now - questionStartTime));
|
let timeRemaining = Math.max(0, questionDuration - (now - questionStartTime));
|
||||||
|
{% if request.session.mode == "learn" %}
|
||||||
|
timeRemaining = questionDuration;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
// Disable all options and highlight selected
|
// Disable all options and highlight selected
|
||||||
const options = document.getElementsByClassName('answer-option');
|
const options = document.getElementsByClassName('answer-option');
|
||||||
@@ -194,14 +220,23 @@
|
|||||||
option.classList.add('opacity-50');
|
option.classList.add('opacity-50');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(input!=""){
|
||||||
// Send answer to server
|
// Send answer to server
|
||||||
gameSocket.send(JSON.stringify({
|
gameSocket.send(JSON.stringify({
|
||||||
type: 'submit_answer',
|
type: 'submit_answer',
|
||||||
participant_id: participantId,
|
participant_id: participantId,
|
||||||
answer: optionIndex,
|
answer:input,
|
||||||
time_remaining: timeRemaining
|
time_remaining: timeRemaining
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
gameSocket.send(JSON.stringify({
|
||||||
|
type: 'submit_answer',
|
||||||
|
participant_id: participantId,
|
||||||
|
answer:optionIndex,
|
||||||
|
time_remaining: timeRemaining
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<p class="text-blue-600 text-xl mb-2">Verbleibende Zeit</p>
|
<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>
|
<p id="remaining-time" class="text-6xl font-bold text-blue-700">30</p>
|
||||||
</div>
|
</div>
|
||||||
|
{% 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
|
||||||
@@ -26,6 +26,17 @@
|
|||||||
</button>
|
</button>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<form action="">
|
||||||
|
<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">
|
||||||
|
<button
|
||||||
|
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">
|
||||||
|
abschicken
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -57,6 +68,13 @@
|
|||||||
|
|
||||||
function submitAnswer(optionIndex) {
|
function submitAnswer(optionIndex) {
|
||||||
if (hasAnswered) return;
|
if (hasAnswered) return;
|
||||||
|
let input = ""; // Declare input here
|
||||||
|
|
||||||
|
try {
|
||||||
|
input = document.getElementById("textanswer").value;
|
||||||
|
} catch (e) {
|
||||||
|
input = "";
|
||||||
|
}
|
||||||
|
|
||||||
hasAnswered = true;
|
hasAnswered = true;
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
@@ -75,14 +93,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(input!=""){
|
||||||
// Send answer to server
|
// Send answer to server
|
||||||
gameSocket.send(JSON.stringify({
|
gameSocket.send(JSON.stringify({
|
||||||
type: 'submit_answer',
|
type: 'submit_answer',
|
||||||
participant_id: participantId,
|
participant_id: participantId,
|
||||||
answer: optionIndex,
|
answer:input,
|
||||||
time_remaining: timeRemaining
|
time_remaining: timeRemaining
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
gameSocket.send(JSON.stringify({
|
||||||
|
type: 'submit_answer',
|
||||||
|
participant_id: participantId,
|
||||||
|
answer:optionIndex,
|
||||||
|
time_remaining: timeRemaining
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Timer
|
// Timer
|
||||||
function updateTimer() {
|
function updateTimer() {
|
||||||
|
|||||||
@@ -10,15 +10,21 @@
|
|||||||
<p class="text-lg mb-2">{{ question_data.question }}</p>
|
<p class="text-lg mb-2">{{ question_data.question }}</p>
|
||||||
<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 class="p-4 rounded-lg {% if option.is_correct %}bg-green-100 border-2 border-green-500 {% else %} bg-gray-100 {% endif %}">
|
|
||||||
|
<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-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">
|
||||||
<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" id="option-count-{{ forloop.counter0 }}">0 Antworten</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if request.session.mode != "learn" %}
|
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<h2 class="text-xl font-bold mb-4">Punktestand</h2>
|
<h2 class="text-xl font-bold mb-4">Punktestand</h2>
|
||||||
<div id="scoreboard" class="space-y-2">
|
<div id="scoreboard" class="space-y-2">
|
||||||
@@ -36,7 +42,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{{ participant.display_name }}
|
{{ participant.display_name }}
|
||||||
</p>
|
</p>
|
||||||
<p class="text-gray-600">{{ participant.score }} Punkte</p>
|
<p data-last-score="{{ participant.last_score }}" class="text-gray-600" id="score-{{ forloop.counter0 }}">{{ participant.score }} Punkte</p>
|
||||||
</div>
|
</div>
|
||||||
{% if participant.last_answer_correct %}
|
{% if participant.last_answer_correct %}
|
||||||
<span class="text-green-500">✓</span>
|
<span class="text-green-500">✓</span>
|
||||||
@@ -48,7 +54,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
{% if is_host %}
|
{% if is_host %}
|
||||||
{% if is_last_question %}
|
{% if is_last_question %}
|
||||||
<button id="finish-button" class="w-full p-3 rounded-full bg-blue-600 text-white font-bold hover:bg-blue-700 transition-colors duration-200">
|
<button id="finish-button" class="w-full p-3 rounded-full bg-blue-600 text-white font-bold hover:bg-blue-700 transition-colors duration-200">
|
||||||
@@ -66,6 +72,7 @@
|
|||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
{% if is_last_question %}
|
{% if is_last_question %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Hilfsfunktion für Pausen
|
// Hilfsfunktion für Pausen
|
||||||
function sleep(ms) {
|
function sleep(ms) {
|
||||||
@@ -174,17 +181,25 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
function updateAnswerStats(stats) {
|
function updateAnswerStats(stats) {
|
||||||
|
const total = Object.values(stats).reduce((a, b) => a + b, 0) || 1;
|
||||||
|
|
||||||
for (var optionIndex in stats) {
|
for (var optionIndex in stats) {
|
||||||
if (stats.hasOwnProperty(optionIndex)) {
|
if (stats.hasOwnProperty(optionIndex)) {
|
||||||
var element = document.getElementById('option-count-' + optionIndex);
|
var countElement = document.getElementById('option-count-' + optionIndex);
|
||||||
if (element) {
|
var fillElement = document.getElementById('option-fill-' + optionIndex);
|
||||||
|
|
||||||
element.textContent = stats[optionIndex] + ' Antwort(en)';
|
if (countElement) {
|
||||||
}
|
countElement.textContent = stats[optionIndex] + ' Antwort(en)';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fillElement) {
|
||||||
|
const percentage = Math.round((stats[optionIndex] / total) * 100);
|
||||||
|
fillElement.style.width = percentage + '%';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Request answer stats when page loads
|
// Request answer stats when page loads
|
||||||
gameSocket.onopen = function(e) {
|
gameSocket.onopen = function(e) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<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="text" 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" 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">
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- Participants List -->
|
<!-- Participants List -->
|
||||||
<div class="mb-6">
|
<div class="mb-6 overflow-y-scroll max-h-96">
|
||||||
<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" />
|
||||||
|
|||||||
35
django/templates/registration/delete_account_confirm.html
Normal file
35
django/templates/registration/delete_account_confirm.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mx-auto px-4">
|
||||||
|
<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="text-center">
|
||||||
|
<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"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<h2 class="mt-4 text-xl font-bold text-gray-900">Löschen bestätigen</h2>
|
||||||
|
|
||||||
|
<p class="mt-2 text-sm text-gray-600">
|
||||||
|
Möchten Sie ihren Account wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="post" class="mt-6">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="flex justify-center space-x-3">
|
||||||
|
<a href="{% url 'accounts:home' %}"
|
||||||
|
class="inline-flex items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
||||||
|
Abbrechen
|
||||||
|
</a>
|
||||||
|
<button type="submit"
|
||||||
|
class="inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">
|
||||||
|
Löschen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
42
django/templates/registration/password_change_form.html
Normal file
42
django/templates/registration/password_change_form.html
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% block title %}Passwort ändern{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<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">
|
||||||
|
<h2 class="text-2xl text-center p-4 font-black">Passwort ändern</h2>
|
||||||
|
<form class="space-y-4" method="post">
|
||||||
|
{% if form.errors %}
|
||||||
|
<div class=" items-center text-red-600 font-black overflow-x-auto break-words text-center">
|
||||||
|
<ul>
|
||||||
|
{% for field, errors in form.errors.items %}
|
||||||
|
{% for error in errors %}
|
||||||
|
<li>{{ error }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="register">
|
||||||
|
|
||||||
|
{{ form.old_password.label_tag }}
|
||||||
|
<input type="password" name="old_password" placeholder="ALTES PASSWORT" />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="register">
|
||||||
|
{{ form.new_password1.label_tag }}
|
||||||
|
<input type="password" name="new_password1" placeholder="NEUES PASSWORT" />
|
||||||
|
</div>
|
||||||
|
<div class="register">
|
||||||
|
{{ form.new_password2.label_tag }}
|
||||||
|
<input type="password" name="new_password2" placeholder="NEUES PASSWORT WIEDERHOLEN" />
|
||||||
|
</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="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>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
19
django/templates/registration/password_reset_complete.html
Normal file
19
django/templates/registration/password_reset_complete.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% block title %}Passwort zurückgesetzt{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<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">
|
||||||
|
<h2 class="text-2xl text-center p-4 font-black">Passwort zurückgesetzt</h2>
|
||||||
|
<div class="space-y-4">
|
||||||
|
Das Passwort wurde erfolgreich zurückgesetzt! Sie können sich nun mit dem neuen Passwort anmelden!
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="mt-4">
|
||||||
|
<a href="{% url 'accounts:login' %}" class="register_link"><button class="w-full p-3 rounded-full bg-blue-600 text-white font-black hover:scale-105 transition duration-200" class="login-button">anmelden</button></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
42
django/templates/registration/password_reset_confirm.html
Normal file
42
django/templates/registration/password_reset_confirm.html
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% block title %}Passwort zurücksetzen{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<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">
|
||||||
|
<h2 class="text-2xl text-center p-4 font-black">Passwort zurücksetzen</h2>
|
||||||
|
{% if validlink %}
|
||||||
|
<form class="space-y-4" method="post">
|
||||||
|
{% if form.errors %}
|
||||||
|
<div class=" items-center text-red-600 font-black overflow-x-auto break-words text-center">
|
||||||
|
<ul>
|
||||||
|
{% for field, errors in form.errors.items %}
|
||||||
|
{% for error in errors %}
|
||||||
|
<li>{{ error }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<div class="register">
|
||||||
|
{{ form.new_password1.label_tag }}
|
||||||
|
<input type="password" name="new_password1" placeholder="NEUES PASSWORT" />
|
||||||
|
</div>
|
||||||
|
<div class="register">
|
||||||
|
{{ form.new_password2.label_tag }}
|
||||||
|
<input type="password" name="new_password2" placeholder="NEUES PASSWORT WIEDERHOLEN" />
|
||||||
|
|
||||||
|
</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="text-center text-sm w-full mt-2 font-light text-blue-600"><a href="{% url 'accounts:home' %}" class="register_link">Doch nicht zurücksetzen?</a></button>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
Dieser Link ist leider nicht mehr gültig oder abgelaufen. Bitte versuchen Sie es erneut:
|
||||||
|
<button class="text-center text-sm w-full mt-2 font-light text-blue-600"><a href="{% url 'accounts:password_reset' %}" class="register_link">Passwort zurücksetzen</a></button>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
18
django/templates/registration/password_reset_done.html
Normal file
18
django/templates/registration/password_reset_done.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% block title %}E-Mail gesendet{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<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">
|
||||||
|
<h2 class="text-2xl font-black mb-4">E-Mail wurde gesendet</h2>
|
||||||
|
<p class="text-gray-700 mb-6">
|
||||||
|
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>
|
||||||
|
|
||||||
|
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
11
django/templates/registration/password_reset_email.html
Normal file
11
django/templates/registration/password_reset_email.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
{% autoescape off %}
|
||||||
|
{% blocktranslate %}Du erhältst diese E-Mail, weil du einen Passwort-Zurücksetzungsversuch bei {{ site_name }} angefragt hast.{% endblocktranslate %}
|
||||||
|
|
||||||
|
{% translate "Bitte gehe zu folgender Seite und wähle ein neues Passwort:" %}
|
||||||
|
{{ protocol }}://{{ domain }}{% url 'accounts:password_reset_confirm' uidb64=uid token=token %}
|
||||||
|
|
||||||
|
{% translate "Dein Benutzername ist:" %} {{ user.get_username }}
|
||||||
|
|
||||||
|
{% blocktranslate %}Danke, dass du {{ site_name }} benutzt!{% endblocktranslate %}
|
||||||
|
{% endautoescape %}
|
||||||
35
django/templates/registration/password_reset_form.html
Normal file
35
django/templates/registration/password_reset_form.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% block title %}Passwort ändern{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<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">
|
||||||
|
<h2 class="text-2xl text-center p-4 font-black">Passwort zurücksetzen</h2>
|
||||||
|
<form class="space-y-4" method="post">
|
||||||
|
Gib hier deine E-Mail an und erhalte eine E-Mail, um das Passwort zurückzusetzen.
|
||||||
|
{% if form.errors %}
|
||||||
|
<div class=" items-center text-red-600 font-black overflow-x-auto break-words text-center">
|
||||||
|
<ul>
|
||||||
|
{% for field, errors in form.errors.items %}
|
||||||
|
{% for error in errors %}
|
||||||
|
<li>{{ error }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="register">
|
||||||
|
{{ form.email.label_tag }}
|
||||||
|
<input type="email" name="email" placeholder="E-MAIL" />
|
||||||
|
</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>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user