feat: project scaffolding - SPA shell, dark theme CSS, hash router, API client

Dieser Commit ist enthalten in:
hafroese 2026-04-02 23:01:01 +02:00
Commit 28150c2e1c
4 geänderte Dateien mit 462 neuen und 0 gelöschten Zeilen

24
edu/js/api.js Normale Datei
Datei anzeigen

@ -0,0 +1,24 @@
'use strict';
var API = {
base: '/api',
request: function(method, path, body) {
var opts = {
method: method,
headers: { 'Content-Type': 'application/json' },
credentials: 'same-origin'
};
if (body) opts.body = JSON.stringify(body);
return fetch(this.base + path, opts).then(function(resp) {
return resp.json().then(function(data) {
if (!resp.ok) throw { status: resp.status, message: data.error || 'Fehler' };
return data;
});
});
},
get: function(path) { return this.request('GET', path); },
post: function(path, body) { return this.request('POST', path, body); },
del: function(path) { return this.request('DELETE', path); }
};

73
edu/js/app.js Normale Datei
Datei anzeigen

@ -0,0 +1,73 @@
'use strict';
var App = {
currentUser: null,
routes: {
dashboard: null, // set after all scripts load
flashcards: null,
tutorials: null,
quiz: null,
cheatsheets: null,
admin: null
},
init: function() {
this.routes.dashboard = Dashboard;
this.routes.flashcards = Flashcards;
this.routes.tutorials = Tutorials;
this.routes.quiz = Quiz;
this.routes.cheatsheets = CheatSheets;
this.routes.admin = Admin;
document.getElementById('login-form').addEventListener('submit', function(e) { Auth.handleLogin(e); });
document.getElementById('logout-btn').addEventListener('click', function() { Auth.handleLogout(); });
window.addEventListener('hashchange', function() { App.route(); });
this.checkAuth();
},
checkAuth: function() {
API.get('/me').then(function(data) {
App.setUser(data.user);
}).catch(function() {
App.showLogin();
});
},
setUser: function(user) {
this.currentUser = user;
document.getElementById('nav-username').textContent = user.display_name;
document.getElementById('login-screen').style.display = 'none';
document.getElementById('app').style.display = 'block';
if (user.is_admin) {
document.querySelector('.nav-admin').style.display = '';
}
this.route();
},
showLogin: function() {
this.currentUser = null;
document.getElementById('login-screen').style.display = 'flex';
document.getElementById('app').style.display = 'none';
},
route: function() {
var hash = location.hash.slice(2) || 'dashboard';
var parts = hash.split('/');
var routeName = parts[0];
var params = parts.slice(1);
document.querySelectorAll('.nav-link').forEach(function(link) {
link.classList.toggle('active', link.dataset.route === routeName);
});
var handler = this.routes[routeName];
if (handler && handler.render) {
handler.render(params);
} else {
document.getElementById('content').textContent = 'Seite nicht gefunden';
}
}
};
document.addEventListener('DOMContentLoaded', function() { App.init(); });