1
0

Compare commits

...

2 Commits

Author SHA1 Message Date
5a2b99c99a vault backup: 2025-12-22 02:56:57
All checks were successful
Deploy Quartz site to GitHub Pages / build (push) Successful in 2m13s
2025-12-22 02:56:57 +01:00
3ae6c10557 vault backup: 2025-12-20 23:33:28 2025-12-22 02:52:24 +01:00
27 changed files with 280 additions and 14 deletions

View File

@@ -34,10 +34,17 @@
"state": {
"type": "pdf",
"state": {
<<<<<<< HEAD
"file": "Anatomi & Histologi 2/Gamla tentor/2023-05-31/!2023-05-31-0100-DKS.pdf"
},
"icon": "lucide-file-text",
"title": "!2023-05-31-0100-DKS"
=======
"file": "Anatomi & Histologi 2/Öga anatomi/Slides.pdf.pdf"
},
"icon": "lucide-file-text",
"title": "Slides.pdf"
>>>>>>> 35528c6 (vault backup: 2025-12-20 23:33:28)
}
}
]
@@ -72,7 +79,11 @@
"state": {
"type": "search",
"state": {
<<<<<<< HEAD
"query": "spoiler-",
=======
"query": "tag:#provfråga lager ",
>>>>>>> 35528c6 (vault backup: 2025-12-20 23:33:28)
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
@@ -83,7 +94,8 @@
"title": "Search"
}
}
]
],
"currentTab": 1
}
],
"direction": "horizontal",
@@ -103,12 +115,20 @@
"state": {
"type": "outgoing-link",
"state": {
<<<<<<< HEAD
"file": "Biokemi/Plasmidlabb/Provfrågor.md",
=======
"file": "Anatomi & Histologi 2/Öga anatomi/Slides.pdf.pdf",
>>>>>>> 35528c6 (vault backup: 2025-12-20 23:33:28)
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
<<<<<<< HEAD
"title": "Outgoing links from Provfrågor"
=======
"title": "Outgoing links from Slides.pdf"
>>>>>>> 35528c6 (vault backup: 2025-12-20 23:33:28)
}
},
{
@@ -192,7 +212,11 @@
}
],
"direction": "horizontal",
<<<<<<< HEAD
"width": 212.5,
=======
"width": 423.5,
>>>>>>> 35528c6 (vault backup: 2025-12-20 23:33:28)
"collapsed": true
},
"left-ribbon": {
@@ -211,6 +235,7 @@
},
"active": "baa45c5e57825965",
"lastOpenFiles": [
<<<<<<< HEAD
"Anatomi & Histologi 2/Gamla tentor/2023-05-31/7.md",
"Anatomi & Histologi 2/Gamla tentor/2023-05-31/6.md",
"Anatomi & Histologi 2/Gamla tentor/2023-05-31/5.md",
@@ -257,6 +282,44 @@
"attachments/image-112.png",
"Anatomi & Histologi 2/Gamla tentor/2025-06-03/!2025-06-03-0003-UJR.pdf",
"Anatomi & Histologi 2/Gamla tentor/2025-02-08/!2025-02-08-0003-ESW.pdf",
=======
"Anatomi & Histologi 2/Öga anatomi/Organa sensum.pdf",
"Anatomi & Histologi 2/Öga anatomi/Slides.pdf.pdf",
"Anatomi & Histologi 2/Gamla tentor/2025-08-08/25.md",
"Anatomi & Histologi 2/Gamla tentor/2025-01-15/29.md",
"Anatomi & Histologi 2/Gamla tentor/2025-02-08/32.md",
"Anatomi & Histologi 2/Öga anatomi/Oculus.md.md",
"Anatomi & Histologi 2/Gamla tentor/2025-01-15/4.md",
"Anatomi & Histologi 2/Öga anatomi/Målbeskrivning.md",
"Anatomi & Histologi 2/Gamla tentor/2022-01-15/23.md",
"Anatomi & Histologi 2/Gamla tentor/2024-01-10/24.md",
"Anatomi & Histologi 2/Gamla tentor/2025-02-08/29.md",
"Anatomi & Histologi 2/Gamla tentor/2025-02-08/30.md",
"Anatomi & Histologi 2/Öga anatomi/Instuderingsfrågor.md",
"Anatomi & Histologi 2/Gamla tentor/Statistik.md",
"Anatomi & Histologi 2/Gamla tentor/2025-08-08/2025-08-08-0030-SHJ.pdf",
"Anatomi & Histologi 2/Gamla tentor/2025-08-08/2025-08-08-0030-SHJ.md",
"Anatomi & Histologi 2/Gamla tentor/2025-02-08/2025-02-08-0003-ESW.pdf",
"Anatomi & Histologi 2/Gamla tentor/2025-02-08/2025-02-08.md",
"Anatomi & Histologi 2/Gamla tentor/2025-06-03/2025-06-03-0003-UJR.pdf",
"Anatomi & Histologi 2/Gamla tentor/2025-08-08/1.md",
"Biokemi/Gamla tentor/2021-12-16/2021-12-16-0073-AXA.pdf",
"Anatomi & Histologi 2/Öra histologi/~$Ögat histologi handout.pptx",
"Anatomi & Histologi 2/Öga histologi/~$Ögat histologi handout.pptx",
"Anatomi & Histologi 2/Gamla tentor/Anatomi och Histologi 2 av Nils.apkg",
"Anatomi & Histologi 2/Gamla tentor/2022-01-06-adrihajdu-Anatomi och histologi 2 quiz.docx",
"z-Tech/Undvika mekanisk memorering AI-stödd studieteknik.md",
"Biokemi/Metabolism/🩸 Heme/Studera.md",
"Anatomi & Histologi 2/Öra histologi/Målbeskrivning.md",
"Anatomi & Histologi 2/Öra histologi/Instuderingsfrågor.md",
"Anatomi & Histologi 2/Öra histologi/25 Ear.md",
"Anatomi & Histologi 2/Öra anatomi/Målbeskrivning.md",
"Anatomi & Histologi 2/Öra anatomi/Slides.md",
"Anatomi & Histologi 2/Öra anatomi/Instuderingsfrågor.md",
"Anatomi & Histologi 2/Öra anatomi/Auris.md.md",
"Anatomi & Histologi 2/Öga histologi/Slides.md",
"attachments/Pasted image 20251128080404.png",
>>>>>>> 35528c6 (vault backup: 2025-12-20 23:33:28)
"Untitled.canvas",
"Biokemi/Metabolism/👋 Introduktion till metabolismen/Untitled.canvas",
"Biokemi/Metabolism/📋 Metabolismen översikt.canvas",

View File

@@ -1,13 +1,13 @@
- Palpebrae och conjunctiva
- Ögats yttersta lager: sclera och cornea
- Ögats mellersta lager (uvea): choroidea, corpus ciliare (inkl. processus ciliares), iris, pupilla
- Linsen (lens): uppbyggnad och funktion
- Corpus vitreum (glaskroppen)
- Ögats innersta lager: retina (endast makroskopisk indelning)
- Palpebrae och ==conjunctiva==
- Ögats yttersta lager: ==sclera== och ==cornea==
- Ögats mellersta lager (uvea): ==choroidea==, corpus ==ciliare== (inkl. processus ciliares (1)), ==iris==, pupilla (1)
- ==Linsen== (lens): uppbyggnad och funktion
- Corpus ==vitreum== (glaskroppen)
- Ögats innersta lager: ==retina== (endast makroskopisk indelning)
- Synens koppling till CNS:
- Nervus opticus (gangliecellers axon)
- Chiasma opticum
- ==Nervus opticus== (gangliecellers axon)
- Chiasma opticum (1)
- Tractus opticus
- Radiatio optica
- Synkortex (primära syncortex)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,26 @@
# Generated by Django 6.0 on 2025-12-22 01:55
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('quiz', '0005_course_exam_question_exam'),
]
operations = [
migrations.CreateModel(
name='Tag',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50, unique=True)),
('slug', models.SlugField(unique=True)),
],
),
migrations.AddField(
model_name='question',
name='tags',
field=models.ManyToManyField(blank=True, related_name='questions', to='quiz.tag'),
),
]

View File

@@ -46,11 +46,20 @@ class Question(models.Model):
file_mtime = models.FloatField(null=True, blank=True) # Track file modification time
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
tags = models.ManyToManyField('Tag', blank=True, related_name='questions')
def __str__(self):
return self.text[:50]
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(max_length=50, unique=True)
def __str__(self):
return self.name
class Option(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='options')
letter = models.CharField(max_length=1)

View File

@@ -80,6 +80,7 @@ def parse_markdown_question(file_path: Path, content: str) -> Tuple[bool, dict]:
- options: list of (letter, text) tuples
- correct_answer: the correct answer letter(s)
- has_answer: whether it has an answer (not TODO)
- tags: list of tag strings
"""
lines = content.split('\n')
@@ -104,7 +105,15 @@ def parse_markdown_question(file_path: Path, content: str) -> Tuple[bool, dict]:
question_type = 'textalternativ'
elif 'frågetyp/textfält' in line:
question_type = 'textfält'
break
elif in_frontmatter and line.strip().lower().startswith('tags:'):
# Extract tags
# Handle: tags: [tag1, tag2] or tags: tag1, tag2
tag_content = line.split(':', 1)[1].strip()
# Remove brackets if present
tag_content = tag_content.strip('[]')
# Split by comma
tags = [t.strip() for t in tag_content.split(',') if t.strip()]
if not is_question:
return False, {}
@@ -138,7 +147,9 @@ def parse_markdown_question(file_path: Path, content: str) -> Tuple[bool, dict]:
'options': [],
'correct_answer': '',
'has_answer': False,
'question_type': question_type
'question_type': question_type,
'tags': tags if 'tags' in locals() else []
}
}
# Extract options (pattern: "- A:" or "- A" for MCQ, or text for textalternativ)
@@ -244,7 +255,9 @@ def parse_markdown_question(file_path: Path, content: str) -> Tuple[bool, dict]:
'options': options_data,
'correct_answer': correct_answer,
'has_answer': has_answer,
'question_type': question_type
'question_type': question_type,
'tags': tags if 'tags' in locals() else []
}
}
@@ -368,6 +381,19 @@ def import_question_file(file_path: Path, base_path: Path, stats: ImportStats, f
stats.created += 1
else:
stats.updated += 1
# Update tags
from django.utils.text import slugify
from quiz.models import Tag
question.tags.clear()
for tag_name in question_data.get('tags', []):
tag_slug = slugify(tag_name)
tag, _ = Tag.objects.get_or_create(
slug=tag_slug,
defaults={'name': tag_name}
)
question.tags.add(tag)
# Update options
question.options.all().delete()

View File

@@ -2,23 +2,46 @@ from django.http import HttpResponse
from django.shortcuts import render
from django.views.decorators.http import require_http_methods
from .models import Question, QuizResult
from .models import Question, QuizResult, Tag
def handle_tag_filter(request):
tag_slug = request.GET.get('tag')
if tag_slug is not None:
if tag_slug == "":
if 'quiz_tag' in request.session:
del request.session['quiz_tag']
else:
request.session['quiz_tag'] = tag_slug
def index(request):
handle_tag_filter(request)
total_questions = Question.objects.count()
answered_count = QuizResult.objects.filter(user=request.quiz_user).count()
context = {
'total_questions': total_questions,
'answered_count': answered_count,
'tags': Tag.objects.all(),
'current_tag': request.session.get('quiz_tag'),
}
return render(request, 'index.html', context)
def get_next_question(request):
# Handle tag filtering
handle_tag_filter(request)
current_tag = request.session.get('quiz_tag')
answered_ids = QuizResult.objects.filter(user=request.quiz_user).values_list('question_id', flat=True)
next_question = Question.objects.exclude(id__in=answered_ids).first()
questions = Question.objects.exclude(id__in=answered_ids)
if current_tag:
questions = questions.filter(tags__slug=current_tag)
next_question = questions.first()
if not next_question:
return render(request, 'partials/complete.html')

View File

@@ -1,6 +1,42 @@
{% extends "base.html" %}
{% block content %}
<style>
.filter-section { margin-bottom: 20px; }
.tag-chip {
display: inline-block;
padding: 5px 12px;
margin: 4px;
border-radius: 16px;
background: #e0e0e0;
text-decoration: none;
color: #333;
font-size: 14px;
transition: background 0.2s;
}
.tag-chip.active {
background: #4CAF50;
color: white;
}
.tag-chip:hover {
background: #d5d5d5;
}
.tag-chip.active:hover {
background: #45a049;
}
</style>
<h1>Quiz Application</h1>
<div class="filter-section">
<a href="?tag=" class="tag-chip {% if not current_tag %}active{% endif %}">All</a>
{% for tag in tags %}
<a href="?tag={{ tag.slug }}" class="tag-chip {% if current_tag == tag.slug %}active{% endif %}">
{{ tag.name }}
</a>
{% endfor %}
</div>
<div class="progress">
<div class="progress-bar" style="width: {% if total_questions > 0 %}{{ answered_count|floatformat:0 }}{% else %}0{% endif %}%"></div>
</div>

83
quiz/uv.lock generated Normal file
View File

@@ -0,0 +1,83 @@
version = 1
revision = 3
requires-python = ">=3.13"
[[package]]
name = "asgiref"
version = "3.11.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/76/b9/4db2509eabd14b4a8c71d1b24c8d5734c52b8560a7b1e1a8b56c8d25568b/asgiref-3.11.0.tar.gz", hash = "sha256:13acff32519542a1736223fb79a715acdebe24286d98e8b164a73085f40da2c4", size = 37969, upload-time = "2025-11-19T15:32:20.106Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/91/be/317c2c55b8bbec407257d45f5c8d1b6867abc76d12043f2d3d58c538a4ea/asgiref-3.11.0-py3-none-any.whl", hash = "sha256:1db9021efadb0d9512ce8ffaf72fcef601c7b73a8807a1bb2ef143dc6b14846d", size = 24096, upload-time = "2025-11-19T15:32:19.004Z" },
]
[[package]]
name = "django"
version = "6.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asgiref" },
{ name = "sqlparse" },
{ name = "tzdata", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/15/75/19762bfc4ea556c303d9af8e36f0cd910ab17dff6c8774644314427a2120/django-6.0.tar.gz", hash = "sha256:7b0c1f50c0759bbe6331c6a39c89ae022a84672674aeda908784617ef47d8e26", size = 10932418, upload-time = "2025-12-03T16:26:21.878Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d7/ae/f19e24789a5ad852670d6885f5480f5e5895576945fcc01817dfd9bc002a/django-6.0-py3-none-any.whl", hash = "sha256:1cc2c7344303bbfb7ba5070487c17f7fc0b7174bbb0a38cebf03c675f5f19b6d", size = 8339181, upload-time = "2025-12-03T16:26:16.231Z" },
]
[[package]]
name = "quiz"
version = "0.1.0"
source = { editable = "." }
dependencies = [
{ name = "django" },
{ name = "watchdog" },
]
[package.metadata]
requires-dist = [
{ name = "django", specifier = ">=6.0.0" },
{ name = "watchdog", specifier = ">=6.0.0" },
]
[package.metadata.requires-dev]
dev = []
[[package]]
name = "sqlparse"
version = "0.5.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" },
]
[[package]]
name = "tzdata"
version = "2025.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" },
]
[[package]]
name = "watchdog"
version = "6.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" },
{ url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" },
{ url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" },
{ url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" },
{ url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" },
{ url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" },
{ url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" },
{ url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" },
{ url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" },
{ url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" },
{ url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" },
{ url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" },
{ url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" },
]