This commit is contained in:
Turtle committed 2025-12-29 13:52:28 +01:00
1 parent 408e115134
commit 31769d1719
13 files changed
+350 -62

No files matched your search

-6
View File
@@ -6,10 +6,8 @@ async function createTemp() {
"level": 1,
"avatar": null,
"abilities": [
"dark_mode"
],
"enabled_abilities": [
"dark_mode"
],
"role": "student",
"courses": [
@@ -22,10 +20,8 @@ async function createTemp() {
"level": 4,
"avatar": "https://static.turtle-coding-gbr.de/profile-pic.png",
"abilities": [
"dark_mode"
],
"enabled_abilities": [
"dark_mode"
],
"role": "professor",
"courses": [
@@ -37,10 +33,8 @@ async function createTemp() {
"level": 4,
"avatar": "https://static.turtle-coding-gbr.de/st",
"abilities": [
"dark_mode"
],
"enabled_abilities": [
"dark_mode"
],
"role": "professor",
"courses": [
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

+4 -1
View File
@@ -208,7 +208,9 @@ content {
background-color: lightgray;
}
.do-not-color-me {
color: black !important;
}
dropdown {
position: fixed;
@@ -244,6 +246,7 @@ dropdown > div:last-child label {
padding-bottom: 8px;
font-weight: normal;
text-align: center;
color: black;
}
dropdown > div:last-child button {
background: none;
+74 -12
View File
@@ -65,6 +65,18 @@ function hideOverlay(id) {
for (var i of elms) _onOverlayDestroy(i);
}
function refreshOverlays() {
const elms = document.getElementsByClassName("overlay");
for (var i of elms) {
const id = i.getAttribute("name");
hideOverlay(id);
showOverlay(id);
}
}
//----------------------------------//
function _main_events() {
const header_bar_1 = document.querySelector(".header_bar_1");
if (header_bar_1 != null) {
@@ -359,6 +371,8 @@ async function getUserData(couchDB) {
}
var userData = null;
const userDataListener = [];
async function setUserData(couchDB) {
const res = await getUserData(couchDB);
if (res == null) {
@@ -367,9 +381,17 @@ async function setUserData(couchDB) {
}
userData = res;
updateAllProfiles(res);
_constructProfile(res);
while (userDataListener.length > 0) {
const call = userDataListener[userDataListener.length - 1];
userDataListener.pop();
try { call(); } catch(err) { console.error(err); }
}
return true;
}
async function updateUserData(couchDB, user) {
async function updateUserData(couchDB, user = userData) {
const res = await couchDB.get("users");
if (res == null) return {"type":"error", "message": "CouchDB failed"};
@@ -385,9 +407,15 @@ async function updateUserData(couchDB, user) {
function updateAllProfiles(user) {
const hasProfilAbility = user.enabled_abilities.includes("profile_pic");
const profiles = document.getElementsByClassName("profile");
for (var i of profiles) {
if (hasProfilAbility) {
i.style.backgroundImage = `url("${user.avatar}")`;
} else {
i.style.removeProperty("backgroundImage");
}
i.onclick = _onProfileClick;
}
}
@@ -412,6 +440,7 @@ function _onProfileClick(event) {
div.innerHTML = `
<label><b>${form1(userData.name)}</b></label>
<button onclick='_onProfilClickOnProfil()'>Profil</button>
<button onclick='showSkillTree()'>Skill-Tree</button>
<button onclick='location.href = "../login.html";'>Abmelden</button>
`;
dropdown.appendChild(div);
@@ -425,28 +454,45 @@ function _onProfilClickOnProfil() {
_showProfile(userData);
}
}
function _showProfile(user) {
let elm = getId("profile_overlay");
if (!elm) {
elm = document.createElement("overlay");
function _constructProfile(user) {
const elm = document.createElement("overlay");
elm.setAttribute("id", "profile_overlay");
document.body.appendChild(elm);
}
elm.innerHTML = `
<div class="overlay_title">Profil-Übersicht</div>
<span style="display: inline-block; width: 100%; text-align: center;">
<div style="border-radius: 50%; width: 80px; height: 80px; display: inline-block; margin-bottom: 10px; background-color: var(--accent_color_bg); background-size: 80px 80px; background-image: url('${user.avatar}');"></div>
<div style="border-radius: 50%; width: 140px; height: 140px; display: inline-block; margin-bottom: 10px; background-color: var(--accent_color_bg); background-size: 140px 140px; background-image: url('');" id="profile-pic" class="profile-pic"></div>
<br>
<u>${!user.title ? "": user.title+" "}${form1(user.name)}</u>
<u style="font-size: 22px;"></u>
<br><br>
</span>
<span class="selectable">
Level: ${user.level ?? 0}<br>
Rolle: ${form1(user.role ?? "Student")}
Level: <label></label><br>
Rolle: <label></label>
</span><br>
Avatar: <input style="" value="${user.avatar}"><br><br>
<button style="font-size: 18px; width: 100%; border-radius: var(--border-radius); font-weight: normal;" onclick="_showProfileSave(this);">Speichern</button>
<span class="avatar-inp">Avatar: <input style="" value=""><br></span><br>
<button style="font-size: 18px; width: 100%; border-radius: var(--border-radius); font-weight: normal; color: black; padding: 5px; background: rgba(255,255,255,0.5);" onclick="_showProfileSave(this);">Speichern</button>
`;
}
function _showProfile(user) {
let elm = getId("profile_overlay");
const hasProfilAbility = user.enabled_abilities.includes("profile_pic");
const avatarInp = elm.querySelector(".avatar-inp");
if (hasProfilAbility) {
elm.querySelector(".profile-pic").style.setProperty("background-image", `url('${user.avatar}')`);
elm.querySelector("input").setAttribute("value", user.avatar);
avatarInp.style.display = "unset";
} else {
avatarInp.style.display = "none";
}
elm.querySelector("u").innerText = getUserDisplayName(user);
const labels = elm.getElementsByTagName("label");
labels[0].innerText = user.level ?? 0;
labels[1].innerText = form1(user.role ?? "Student");
showOverlay("profile_overlay");
}
async function _showProfileSave(elm) {
@@ -481,3 +527,19 @@ async function playSound(src) {
console.log("Error playing audio:", err);
}
}
function hexToRGBA(hex) {
let r = 0, g = 0, b = 0;
if (hex.length === 7) {
r = parseInt(hex.slice(1, 3), 16);
g = parseInt(hex.slice(3, 5), 16);
b = parseInt(hex.slice(5, 7), 16);
}
return [r, g, b];
}
function getUserDisplayName(user) {
const hasHonor = (user.enabled_abilities ??= []).includes("title_of_honor");
const title_of_honor = hasHonor ? "(Sir) " : "";
return `${title_of_honor}${ !user.title ? "" : user.title + " " }${ form1(user.name) }`;
}
+207
View File
@@ -0,0 +1,207 @@
const getSkillTree = () => ({
id: "root",
text: "Skill-Tree",
children: [
{
text: "Dark-Mode",
id: "dark_mode",
description: "Ändert das Aussehen zu einem dunklen Design!",
collision: ["pink_mode"],
children: [
{
text: "Pink-Mode",
description: "Ändert das Aussehen zu einem pinken Design!",
id: "pink_mode",
collision: ["dark_mode"],
},
{
text: "Accent-Color",
description: "Verändere die Primärfarbe",
id: "accent_color",
call: `chooseAccentColor();`,
call_unset: `unsetAccentColor()`
}
]
},
{
text: "Profilbild",
id: "profile_pic",
description: "Erlange die Fähigkeit, das Profilbild zu ändern",
children: [
{
text: "Einfacher Rahmen",
id: "simple_border",
description: "Ein einfacher Rahmen, der sich um das Profilbild legt",
collision: ["gold_border", "epic_border"],
children: [
{
text: "Gold-Rahmen",
id: "gold_border",
description: "Ein goldener Rahmen, der sich um das Profilbild legt",
collision: ["simple_border", "epic_border"],
children: []
},
{
text: "Epic-Rahmen",
id: "epic_border",
description: "Ein epischer Rahmen, der sich um das Profilbild legt",
collision: ["simple_border", "gold_border"],
children: [
{
text: "Ehren-Titel",
id: "title_of_honor",
description: "Kriege den Ehrentitel \"Sir\" verliehen"
}
]
}
]
}
],
}
]
});
const _skillCb = {
"dark_mode": function() {
document.body.style = "background: black; color: white;";
},
"dark_mode_unset": function() {
document.body.style = "background: unset; color: unset;";
},
"pink_mode": function() {
document.body.style = `background: rgba(242, 199, 252, 1); color: #5a076d;`;
},
"pink_mode_unset": function() {
_skillCb.dark_mode_unset();
},
"accent_color": function() {
const storage = (userData.skillStorage ??= {})["accent_color"];
if (!storage) return;
const rgb = storage.join(",");
setRootStyle("--accent_color_fg", `rgba(${rgb}, 1)`);
setRootStyle("--accent_color_fg_o", `rgba(${rgb}, 0.5)`);
setRootStyle("--accent_color_bg", `rgba(${rgb}, 1)`);
setRootStyle("--accent_color_bg_o", `rgba(${rgb}, 0.5)`);
setRootStyle("--accent_color_bg_o2", `rgba(${rgb}, 0.25)`);
},
"accent_color_unset": function() {
removeRootStyle("--accent_color_fg");
removeRootStyle("--accent_color_fg_o");
removeRootStyle("--accent_color_bg");
removeRootStyle("--accent_color_bg_o");
removeRootStyle("--accent_color_bg_o2");
},
"simple_border": function() {
setProfileBorder("../imgs/simple_border.png", 8);
},
"unset_simple_border": () => unsetProfileBorder(),
"gold_border": function() {
setProfileBorder("../imgs/gold_border.png", 8);
},
"unset_gold_border": () => unsetProfileBorder(),
"epic_border": function() {
setProfileBorder("../imgs/epic_border.png", 8);
},
"unset_epic_border": () => unsetProfileBorder(),
"title_of_honor": function() {},
"profile_pic": () => updateAllProfiles(userData)
};
function chooseAccentColor() {
var elm = getId("skill_chooseAccentColor");
if (!elm) {
elm = document.createElement("overlay");
elm.setAttribute("id", "skill_chooseAccentColor");
elm.innerHTML = `
<div class="overlay_title">Wähle eine Farbe:</div><br>
<input type="color" style="width: 100%; border-radius: var(--border-radius);"><br><br>
<button onclick="setAccentColor(this)" style="width: 100%; border-radius: var(--border-radius); font-size: 18px; padding: 10px; background: rgba(255, 255, 255, 0.5);">Bestätigen</button>
`;
document.body.appendChild(elm);
}
setTimeout(() => showOverlay("skill_chooseAccentColor"), 1);
}
function unsetAccentColor() {
userData.skillStorage ??= {};
userData.skillStorage["accent_color"] = null;
updateUserData(new CouchDB());
}
function setAccentColor(elm) {
const input = elm.parentElement.querySelector("input");
const rgba = hexToRGBA(input.value);
userData.skillStorage ??= {};
userData.skillStorage["accent_color"] = rgba;
updateUserData(new CouchDB());
hideOverlay("skill_chooseAccentColor");
_skillCb.accent_color();
refreshOverlays();
}
//--------------------------------------------//
function unsetProfileBorder() {
const elms = document.getElementsByClassName("profile");
for (var i of elms) i.innerHTML = '';
}
function setProfileBorder(src, x) {
const elms = document.getElementsByClassName("profile");
const style1 = `
width: 67px;
height: 67px;
border-radius: 50%;
border: none;
background-size: 67px 67px;
position: absolute;
background-image: url('${src}');
transform: translate(-${x}px, calc(-50%));
`;
for (var i of elms) {
i.innerHTML = `<div class="border" style="${style1}"></div>`;
}
const style2 = `
width: 160px;
height: 160px;
border-radius: 50%;
border: none;
background-size: 160px 160px;
position: absolute;
background-image: url('${src}');
transform: translate(-${x*1.2}px, -8px);
`;
const profilPic = getId("profile-pic");
if (profilPic) {
profilPic.innerHTML = `<div class="border" style="${style2}"></div>`;
}
}
function setRootStyle(key, value) {
document.documentElement.style.setProperty(key, value);
}
function removeRootStyle(key) {
document.documentElement.style.removeProperty(key);
}
function exeSkill(id, activate = true) {
const cb = _skillCb[activate ? id: id+"_unset"];
if (typeof(cb) != "function") return;
try { cb(); } catch(err) { console.error(err); }
}
var globalSkills = [];
async function runSkills() {
const skills = userData.enabled_abilities;
globalSkills = skills;
for (var i of skills) exeSkill(i, true);
}
userDataListener.push(runSkills);
+32 -43
View File
@@ -2,46 +2,6 @@
//=> use playLevelSound() -> void;
//=> use playXPSound() -> void;
const getSkillTree = () => ({
id: "root",
text: "Skill-Tree",
children: [
{
text: "DarkMode",
id: "dark_mode",
description: "Setzt die Theme auf dunkel!",
children: [
{
text: "Bla",
description: "Lorem ipsum et idk! Lorem ipsum et idk! Lorem ipsum et idk! Lorem ipsum et idk! Lorem ipsum et idk! Lorem ipsum et idk! Lorem ipsum et idk! Lorem ipsum et idk!",
id: "pink_mode",
children: []
}
]
},
{
text: "1",
id: "1",
description: "one",
children: [
{
text: "2",
id: "2",
description: "two",
children: []
},
{
text: "3",
id: "3",
description: "three",
children: []
}
]
}
]
});
var aSkillPoints = 0;
function showSkillTree() {
@@ -52,6 +12,8 @@ function showSkillTree() {
document.body.appendChild(elm);
}
elm.innerHTML = ``;
const div = document.createElement("div");
div.style = `
display: inline-block;
@@ -60,6 +22,7 @@ height: 100%;
overflow: auto;
margin-top: 20px;
text-align: center;
color: black;
`;
var res = generateSkillTree(getSkillTree(), userData.abilities)
@@ -77,7 +40,7 @@ text-align: center;
margin-top: 20px;
`;
div2.innerHTML = `
<div style="padding: 10px 30px; background: rgba(255, 255, 255, 0.6); border-radius: var(--border-radius); display: inline-block;">
<div style="padding: 10px 30px; background: rgba(255, 255, 255, 0.6); border-radius: var(--border-radius); display: inline-block;" class="do-not-color-me">
Skill-Points: <span class="aSkillPoints">${aSkillPoints}</span>
</div>
`;
@@ -99,7 +62,7 @@ function _getRect(parent, data) {
elm.innerHTML = '';
const div = document.createElement("div");
div.style = `display: inline-block; width: 100%; min-width: 300px; text-align: center;`;
div.style = `display: inline-block; width: 100%; min-width: 300px; text-align: center; color: black;`;
div.innerHTML = `
<b style="display: inline-block; margin-top: 5px;">${data.text}</b><br><br>
<span>${data.description}</span><br><br>
@@ -138,15 +101,25 @@ async function activateSkill(elm, data) {
const isEnabled = eAblities.includes(data.id);
if (isEnabled) {
//disabled
userData.enabled_abilities = eAblities.filter((val) => val != data.id);
for (var elm of elms) {
elm.setAttribute("fill", "rgb(187, 243, 183)");
}
} else {
//enabled
const coll = data.collision ??= [];
userData.enabled_abilities = eAblities.filter((val) => !coll.includes(val));
userData.enabled_abilities.push(data.id);
for (var elm of elms) {
elm.setAttribute("fill", "lightgreen");
}
for (var i of coll) {
exeSkill(i, false);
for (var elm of document.getElementsByClassName("skill_" + i)) {
elm.setAttribute("fill", "rgb(187, 243, 183)");
}
}
}
elm.innerText = !isEnabled ? "Deaktivieren" : "Aktivieren";
@@ -154,6 +127,19 @@ async function activateSkill(elm, data) {
getOverlay("skill_tree_details_overlay").innerHTML = "";
await updateUserData(new CouchDB(), userData);
hideOverlay("skill_tree_details_overlay");
if (!isEnabled) {
if (typeof(data.call) == "string") {
try { eval(data.call); } catch (err) { console.error(err); }
}
}
exeSkill(data.id, !isEnabled);
if (isEnabled) {
if (typeof(data.call_unset) == "string") {
try { eval(data.call_unset); } catch (err) { console.error(err); }
}
}
refreshOverlays();
}
async function _buySkill(data) {
const elms = document.getElementsByClassName("skill_" + data.id);
@@ -170,6 +156,8 @@ async function _buySkill(data) {
userData.abilities.push(data.id);
playXPSound();
getOverlay("skill_tree_details_overlay").innerHTML = "";
await updateUserData(new CouchDB(), userData);
@@ -187,6 +175,7 @@ function generateSkillTree(skillTree, abilities) {
/* -------- calc layout -------- */
function measure_tree(data) {
data.children ??= [];
if (data.children.length === 0) {
data._width = nWidth;
} else {
@@ -196,6 +185,7 @@ function generateSkillTree(skillTree, abilities) {
}
return data._width;
}
measure_tree(skillTree);
function calc_tree(data, x, y) {
data._x = x;
@@ -211,7 +201,6 @@ function generateSkillTree(skillTree, abilities) {
});
}
measure_tree(skillTree);
calc_tree(skillTree, 0, 0);
/* -------- bounding-stuff -------- */
+2
View File
@@ -6,6 +6,8 @@
<link rel="stylesheet" href="../lib/basic.css">
<script src="../auth.js"></script>
<script src="../lib/basic.js"></script>
<script src="../other/skills.js"></script>
<script src="../other/skilltree.js"></script>
</head>
<body>
<style>
+2
View File
@@ -6,6 +6,8 @@
<link rel="stylesheet" href="../lib/basic.css">
<script src="../auth.js"></script>
<script src="../lib/basic.js"></script>
<script src="../other/skills.js"></script>
<script src="../other/skilltree.js"></script>
<script src="https://cdn.jsdelivr.net/npm/qrcodejs/qrcode.min.js"></script>
<script>
const couchDB = new CouchDB();
+2
View File
@@ -6,6 +6,8 @@
<link rel="stylesheet" href="../lib/basic.css">
<script src="../auth.js"></script>
<script src="../lib/basic.js"></script>
<script src="../other/skills.js"></script>
<script src="../other/skilltree.js"></script>
<script>
const couchDB = new CouchDB();
setUserData(couchDB);
+25
View File
@@ -0,0 +1,25 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../lib/basic.css">
<script src="../auth.js"></script>
<script src="../lib/basic.js"></script>
<script src="./uebersicht_overlay.js"></script>
<script src="../other/skills.js"></script>
<script src="../other/skilltree.js"></script>
<title>Übersicht</title>
</head>
<body>
<script>
const couchDB = new CouchDB();
setUserData(couchDB).then((val) => {
});
</script>
</body>
</html>
+2
View File
@@ -3,6 +3,8 @@
<link rel="stylesheet" href="../lib/basic.css">
<script src="../auth.js"></script>
<script src="../lib/basic.js"></script>
<script src="../other/skills.js"></script>
<script src="../other/skilltree.js"></script>
<head>
<meta charset="UTF-8">
<title>Beispielseite</title>