Merge branch 'master' of ssh://gitea.cato447.de:222/cato447/tutor-tool

This commit is contained in:
2025-10-20 20:57:14 +02:00
18 changed files with 1949 additions and 156 deletions

View File

@@ -102,7 +102,7 @@ def index():
if not token: if not token:
return redirect(url_for("main.set_token")) return redirect(url_for("main.set_token"))
else: else:
return render_template('index.html', active_banner=get_active_banner(), decks=get_unlocked_decks(token), user_name=token.name, active_course=token.active_course, courses=get_all_courses()) return render_template('index.html', active_banner=get_active_banner(), decks=get_unlocked_decks(token), user_name=token.name, active_course_name=token.active_course.name, courses=get_all_courses())
def set_cookie(token): def set_cookie(token):
next_url = session.pop('next_url', None) next_url = session.pop('next_url', None)
@@ -306,8 +306,7 @@ def serve_deck(deck, course_folder, path='index.html'):
@main.route('/admin', methods=['GET', 'POST']) @main.route('/admin', methods=['GET', 'POST'])
@flask_login.login_required @flask_login.login_required
def admin(): def admin():
active_course_id = flask_login.current_user.active_course_id active_course = get_course(flask_login.current_user.active_course_id)
active_course = get_course(active_course_id)
if active_course is None: if active_course is None:
raise Exception raise Exception
deck_form = DeckForm() deck_form = DeckForm()
@@ -353,7 +352,7 @@ def admin():
print(f"Error in {getattr(password_form, field).label.text}: {error}", flush=True) print(f"Error in {getattr(password_form, field).label.text}: {error}", flush=True)
return redirect(url_for('main.admin')) return redirect(url_for('main.admin'))
return render_template("admin.html", deck_form=deck_form, password_form=password_form, decks=decks, passwords=get_passwords(active_course), courses=get_all_courses(), active_course_id=active_course_id) return render_template("admin.html", deck_form=deck_form, password_form=password_form, decks=decks, passwords=get_passwords(active_course), courses=get_all_courses(), active_course_name=active_course.name)
@main.route('/admin/switch_course/<new_course>', methods=['POST']) @main.route('/admin/switch_course/<new_course>', methods=['POST'])
@flask_login.login_required @flask_login.login_required

1
app/static/css/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
output.css

3
app/static/css/input.css Normal file
View File

@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="Discord-Logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 126.644 96"><defs><style>.cls-1{fill:#5865f2;}</style></defs><path id="Discord-Symbol-Blurple" class="cls-1" d="M81.15,0c-1.2376,2.1973-2.3489,4.4704-3.3591,6.794-9.5975-1.4396-19.3718-1.4396-28.9945,0-.985-2.3236-2.1216-4.5967-3.3591-6.794-9.0166,1.5407-17.8059,4.2431-26.1405,8.0568C2.779,32.5304-1.6914,56.3725.5312,79.8863c9.6732,7.1476,20.5083,12.603,32.0505,16.0884,2.6014-3.4854,4.8998-7.1981,6.8698-11.0623-3.738-1.3891-7.3497-3.1318-10.8098-5.1523.9092-.6567,1.7932-1.3386,2.6519-1.9953,20.281,9.547,43.7696,9.547,64.0758,0,.8587.7072,1.7427,1.3891,2.6519,1.9953-3.4601,2.0457-7.0718,3.7632-10.835,5.1776,1.97,3.8642,4.2683,7.5769,6.8698,11.0623,11.5419-3.4854,22.3769-8.9156,32.0509-16.0631,2.626-27.2771-4.496-50.9172-18.817-71.8548C98.9811,4.2684,90.1918,1.5659,81.1752.0505l-.0252-.0505ZM42.2802,65.4144c-6.2383,0-11.4159-5.6575-11.4159-12.6535s4.9755-12.6788,11.3907-12.6788,11.5169,5.708,11.4159,12.6788c-.101,6.9708-5.026,12.6535-11.3907,12.6535ZM84.3576,65.4144c-6.2637,0-11.3907-5.6575-11.3907-12.6535s4.9755-12.6788,11.3907-12.6788,11.4917,5.708,11.3906,12.6788c-.101,6.9708-5.026,12.6535-11.3906,12.6535Z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
app/static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 773.12 773.12"><linearGradient id="a" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#50adff"/><stop offset="1" stop-color="#7877fc"/></linearGradient><circle cx="386.56" cy="386.56" r="386.56" fill="url(#a)"/><path d="M566.66 527.25c0 33.03-24.23 60.05-53.84 60.05H260.29c-29.61 0-53.84-27.02-53.84-60.05 0-20.22 9.09-38.2 22.93-49.09l134.37-120c2.5-2.14 5.74 1.31 3.94 4.19l-49.29 98.69c-1.38 2.76.41 6.16 3.25 6.16h191.18c29.61 0 53.83 27.03 53.83 60.05zm0-281.39c0 20.22-9.09 38.2-22.93 49.09l-134.37 120c-2.5 2.14-5.74-1.31-3.94-4.19l49.29-98.69c1.38-2.76-.41-6.16-3.25-6.16H260.29c-29.61 0-53.84-27.02-53.84-60.05s24.23-60.05 53.84-60.05h252.54c29.61 0 53.83 27.02 53.83 60.05z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 767 B

View File

@@ -6,31 +6,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Deck Admin</title> <title>Deck Admin</title>
<!-- Tailwind CSS v4.1.4 CDN --> <link rel="stylesheet" href="{{ url_for('static', filename='css/output.css') }}">
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script> <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
<!-- Tailwind Config (Dark Mode + Theme Colors) -->
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
background: '#121418', // dark slate with blue/gray tone
surface: '#1e2127', // a bit lighter for containers/cards
border: '#2a2d34', // visible but subtle borders
primary: '#4f8cff', // soft blue that pops but is not neon
text: '#e4e4e7', // light gray for high contrast
muted: '#a0a0ad', // for subdued text
},
},
}
};
</script>
<!-- Flowbite -->
<link href="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.css" rel="stylesheet">
</head> </head>
<body class="bg-background text-text min-h-screen font-sans"> <body class="bg-background text-text min-h-screen font-sans">
<nav class="bg-white border-gray-200 dark:bg-gray-900"> <nav class="bg-white border-gray-200 dark:bg-gray-900">
@@ -42,12 +21,8 @@
<div class="relative group"> <div class="relative group">
<button class="flex items-center text-gray-900 dark:text-white hover:text-blue-700 dark:hover:text-blue-500 font-medium py-2 px-3 rounded-lg bg-transparent"> <button class="flex items-center text-gray-900 dark:text-white hover:text-blue-700 dark:hover:text-blue-500 font-medium py-2 px-3 rounded-lg bg-transparent">
{% for course in courses %} {{active_course_name}}
{% if course.id == active_course_id %} <svg class="w-2.5 h-2.5 ms-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
{{ course.name }}
{% endif %}
{% endfor %}
<svg class="w-2.5 h-2.5 ms-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
</svg> </svg>
</button> </button>

View File

@@ -4,15 +4,8 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Login</title> <title>Login</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Tailwind CSS --> <link rel="stylesheet" href="{{ url_for('static', filename='css/output.css') }}">
<script src="https://cdn.tailwindcss.com"></script> <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
<!-- Flowbite -->
<script src="https://unpkg.com/flowbite@2.3.0/dist/flowbite.min.js"></script>
<script>
tailwind.config = {
darkMode: 'class',
};
</script>
</head> </head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex items-center justify-center"> <body class="bg-gray-900 text-gray-100 min-h-screen flex items-center justify-center">

View File

@@ -1,33 +1,14 @@
<!DOCTYPE html>
<html lang="en" class="dark"> <html lang="en" class="dark">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Banner</title> <title>Banner</title>
<!-- Tailwind CSS v4.1.4 CDN --> <link rel="stylesheet" href="{{ url_for('static', filename='css/output.css') }}">
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script>
<!-- Tailwind Config (Dark Mode + Theme Colors) --> <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
background: '#121418', // dark slate with blue/gray tone
surface: '#1e2127', // a bit lighter for containers/cards
border: '#2a2d34', // visible but subtle borders
primary: '#4f8cff', // soft blue that pops but is not neon
text: '#e4e4e7', // light gray for high contrast
muted: '#a0a0ad', // for subdued text
},
},
}
};
</script>
<!-- Flowbite -->
<link href="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.css" rel="stylesheet" />
</head> </head>
<body class="bg-background text-text min-h-screen font-sans"> <body class="bg-background text-text min-h-screen font-sans">

View File

@@ -3,30 +3,8 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Live Confusion Alerts</title> <title>Live Confusion Alerts</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/output.css') }}">
<!-- Tailwind DEV CDN (for production, use your compiled CSS) --> <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.1/socket.io.min.js"></script>
<!-- Tailwind Config (Dark Mode + Theme Colors) -->
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
background: '#121418', // dark slate with blue/gray tone
surface: '#1e2127', // a bit lighter for containers/cards
border: '#2a2d34', // visible but subtle borders
primary: '#4f8cff', // soft blue that pops but is not neon
text: '#e4e4e7', // light gray for high contrast
muted: '#a0a0ad', // for subdued text
},
},
}
};
</script>
</head> </head>
<body class="bg-background min-h-screen"> <body class="bg-background min-h-screen">
<nav class="bg-white border-gray-200 dark:bg-gray-900"> <nav class="bg-white border-gray-200 dark:bg-gray-900">

View File

@@ -5,37 +5,14 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tutorial Materials</title> <title>Tutorial Materials</title>
<!-- Tailwind CSS v4.1.4 CDN --> <link rel="stylesheet" href="{{ url_for('static', filename='css/output.css') }}">
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script>
<!-- Tailwind Config (Dark Mode + Theme Colors) --> <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
background: '#121418', // dark slate with blue/gray tone
surface: '#1e2127', // a bit lighter for containers/cards
border: '#2a2d34', // visible but subtle borders
primary: '#4f8cff', // soft blue that pops but is not neon
text: '#e4e4e7', // light gray for high contrast
muted: '#a0a0ad', // for subdued text
},
},
}
};
</script>
<!-- Flowbite -->
<link href="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.css" rel="stylesheet" />
<!-- in base.html, in <head> or just before </body> --> <!-- in base.html, in <head> or just before </body> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.1/socket.io.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.1/socket.io.min.js"></script>
<script src="https://unpkg.com/htmx.org@1.9.10"></script> <script src="https://unpkg.com/htmx.org@1.9.10"></script>
</head> </head>
@@ -45,7 +22,7 @@
<header class="bg-surface border-b border-border shadow-sm"> <header class="bg-surface border-b border-border shadow-sm">
<div class="w-full px-6 py-4 flex items-center justify-between" > <div class="w-full px-6 py-4 flex items-center justify-between" >
<div class="flex items-center space-x-3"> <div class="flex items-center space-x-2">
<span class="text-gray-700 dark:text-gray-200 text-base font-medium whitespace-nowrap"> <span class="text-gray-700 dark:text-gray-200 text-base font-medium whitespace-nowrap">
User: {{ user_name }} User: {{ user_name }}
</span> </span>
@@ -60,7 +37,14 @@
</form> </form>
</div> </div>
<div class="relative z-10"> <div class="flex items-center space-x-3">
<a href="https://zulip.in.tum.de/#narrow/channel/3234-ITSec-Tutorium-Simon-Bu.C3.9Fmann" target="_blank">
<img src="{{ url_for('static', filename='zulip_icon.svg') }}" class="h-8 w-8">
</a>
<a href="https://discordapp.com/users/306086176585154560" target="_blank" class="mr-6">
<img src="{{ url_for('static', filename='discord_icon.svg') }}" class="h-8 w-8">
</a>
<a href="/admin"> <a href="/admin">
<button class="bg-primary hover:bg-blue-700 text-white px-3 py-1 rounded-md transition"> <button class="bg-primary hover:bg-blue-700 text-white px-3 py-1 rounded-md transition">
Admin Admin
@@ -83,11 +67,7 @@
<div class="flex justify-center"> <div class="flex justify-center">
<div class="relative group"> <div class="relative group">
<button class="flex items-center text-gray-900 dark:text-white hover:text-blue-700 dark:hover:text-blue-500 font-medium py-1 px-3 rounded-lg bg-transparent text-2xl"> <button class="flex items-center text-gray-900 dark:text-white hover:text-blue-700 dark:hover:text-blue-500 font-medium py-1 px-3 rounded-lg bg-transparent text-2xl">
{% for course in courses %} {{active_course_name}}
{% if course.id == active_course.id %}
{{ course.name }}
{% endif %}
{% endfor %}
<svg class="w-2.5 h-2.5 ms-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6"> <svg class="w-2.5 h-2.5 ms-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
</svg> </svg>
@@ -167,19 +147,5 @@
<script src="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/flowbite@3.1.2/dist/flowbite.min.js"></script>
<script>
function enableUsernameEdit() {
const input = document.getElementById('usernameInput');
const editBtn = document.getElementById('editBtn');
const saveBtn = document.getElementById('saveBtn');
input.removeAttribute('disabled');
input.classList.add('border-border');
input.focus();
editBtn.classList.add('hidden');
saveBtn.classList.remove('hidden');
}
</script>
</body> </body>
</html> </html>

View File

@@ -4,16 +4,10 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Register for Tutortool</title> <title>Register for Tutortool</title>
<script src="https://cdn.tailwindcss.com"></script> <link rel="stylesheet" href="{{ url_for('static', filename='css/output.css') }}">
<style> <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
body {
@apply bg-background text-text font-sans;
background-color: #1a202c;
color: #a0aec0;
}
</style>
</head> </head>
<body class="flex items-center justify-center min-h-screen"> <body class="flex items-center justify-center min-h-screen bg-background">
<div class="bg-gray-800 p-8 rounded-lg shadow-lg max-w-md w-full border border-gray-700"> <div class="bg-gray-800 p-8 rounded-lg shadow-lg max-w-md w-full border border-gray-700">
<div class="text-center mb-6"> <div class="text-center mb-6">
<h1 class="text-3xl font-bold text-white mb-2">Create an Account</h1> <h1 class="text-3xl font-bold text-white mb-2">Create an Account</h1>
@@ -58,7 +52,7 @@
</button> </button>
</form> </form>
<p class="text-center mt-4 text-sm"> <p class="text-center mt-4 text-sm text-text">
Already have an account? <a href="/set_token" class="text-blue-400 hover:underline">Log In</a> Already have an account? <a href="/set_token" class="text-blue-400 hover:underline">Log In</a>
</p> </p>
</div> </div>

View File

@@ -4,16 +4,10 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Register for Tutortool</title> <title>Register for Tutortool</title>
<script src="https://cdn.tailwindcss.com"></script> <link rel="stylesheet" href="{{ url_for('static', filename='css/output.css') }}">
<style> <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
body {
@apply bg-background text-text font-sans;
background-color: #1a202c;
color: #a0aec0;
}
</style>
</head> </head>
<body class="flex items-center justify-center min-h-screen"> <body class="flex items-center justify-center min-h-screen bg-background">
<div class="bg-gray-800 p-8 rounded-lg shadow-lg max-w-md w-full border border-gray-700"> <div class="bg-gray-800 p-8 rounded-lg shadow-lg max-w-md w-full border border-gray-700">
<div class="text-center mb-6"> <div class="text-center mb-6">
<h1 class="text-3xl font-bold text-white mb-2">Login</h1> <h1 class="text-3xl font-bold text-white mb-2">Login</h1>
@@ -44,7 +38,7 @@
</button> </button>
</form> </form>
<p class="text-center mt-4 text-sm"> <p class="text-center mt-4 text-sm text-text">
Do not have an Account? <a href="/register" class="text-blue-400 hover:underline">Create one</a> Do not have an Account? <a href="/register" class="text-blue-400 hover:underline">Create one</a>
</p> </p>
</div> </div>

1856
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

23
package.json Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "tutor",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build:css": "npx tailwindcss -i app/static/css/input.css -o app/static/css/output.css --minify"
},
"repository": {
"type": "git",
"url": "ssh://git@gitea.cato447.de:222/cato447/tutor-tool.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"devDependencies": {
"autoprefixer": "^10.4.21",
"flowbite": "^3.1.2",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.17"
}
}

6
postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@@ -1,5 +1,7 @@
#/bin/bash #/bin/bash
npm run build:css
nohup .venv/bin/gunicorn \ nohup .venv/bin/gunicorn \
--bind 127.0.0.1:5000 \ --bind 127.0.0.1:5000 \
--worker-class eventlet \ --worker-class eventlet \

20
tailwind.config.js Normal file
View File

@@ -0,0 +1,20 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./app/templates/**/*.html"], // <-- MUST BE CORRECT
darkMode: 'class',
theme: {
extend: {
colors: {
background: '#121418',
surface: '#1e2127',
border: '#2a2d34',
primary: '#4f8cff',
text: '#e4e4e7',
muted: '#a0a0ad',
},
},
},
plugins: [
require('flowbite/plugin')
],
}