Changed: DB Params

This commit is contained in:
2025-03-20 12:35:13 +01:00
parent 8640a12439
commit b71b3d12ca
822 changed files with 134218 additions and 0 deletions

9
assets/css/colors.css Normal file
View File

@@ -0,0 +1,9 @@
:root {
--text-color: #E0E1DD;
--text-color-inverted: #1f1e22;
--background-color: #0d1b2a;
--focused: #f4a260;
--unfocused: #2ec4b6;
--menu-bg: #1b3857;
--menu-border: #668580;
}

View File

@@ -0,0 +1,36 @@
.two-split {
display: grid;
grid-template-columns: 1fr 4fr;
grid-auto-rows: 75px;
}
.three-split {
display: grid;
grid-template-columns: 1fr 4fr 1fr;
grid-auto-rows: 75px;
}
.grid-item-left {
display: flex;
align-items: center;
padding-left: 10%;
justify-content: left;
}
.grid-item-center {
display: flex;
align-items: center;
justify-content: center;
}
.one-row {
grid-template-rows: 1fr;
}
.two-row {
grid-template-rows: 1fr 1fr;
}
.three-row {
grid-template-rows: 1fr 1fr 1fr;
}

319
assets/css/style.css Normal file
View File

@@ -0,0 +1,319 @@
@font-face {
font-family: "Lato";
src:
url("/assets/fonts/lato/Lato-BlackItalic.ttf") format("truetype"),
url("/assets/fonts/lato/Lato-Black.ttf") format("truetype"),
url("/assets/fonts/lato/Lato-BoldItalic.ttf") format("truetype"),
url("/assets/fonts/lato/Lato-Bold.ttf") format("truetype"),
url("/assets/fonts/lato/Lato-Italic.ttf") format("truetype"),
url("/assets/fonts/lato/Lato-LightItalic.ttf") format("truetype"),
url("/assets/fonts/lato/Lato-Regular.ttf") format("truetype"),
url("/assets/fonts/lato/Lato-ThinItalic.ttf") format("truetype"),
url("/assets/fonts/lato/Lato-Thin.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
.lato-thin {
font-family: "Lato", sans-serif;
font-weight: 100;
font-style: normal;
}
.lato-light {
font-family: "Lato", sans-serif;
font-weight: 300;
font-style: normal;
}
.lato-regular {
font-family: "Lato", sans-serif;
font-weight: 400;
font-style: normal;
}
.lato-bold {
font-family: "Lato", sans-serif;
font-weight: 700;
font-style: normal;
}
.lato-black {
font-family: "Lato", sans-serif;
font-weight: 900;
font-style: normal;
}
.lato-thin-italic {
font-family: "Lato", sans-serif;
font-weight: 100;
font-style: italic;
}
.lato-light-italic {
font-family: "Lato", sans-serif;
font-weight: 300;
font-style: italic;
}
.lato-regular-italic {
font-family: "Lato", sans-serif;
font-weight: 400;
font-style: italic;
}
.lato-bold-italic {
font-family: "Lato", sans-serif;
font-weight: 700;
font-style: italic;
}
.lato-black-italic {
font-family: "Lato", sans-serif;
font-weight: 900;
font-style: italic;
}
* {
color: var(--text-color);
font-family: lato-regular, sans-serif;
box-sizing: inherit;
}
body {
background-color: var(--background-color);
}
main {
position: absolute;
left: 50%;
transform: translate(-50%, 0%);
min-height: 110vh;
width: 90%;
}
footer {
position: fixed;
left: 0;
bottom: 0;
background-color: var(--menu-bg);
width: 100vw;
}
a {
color: var(--unfocused);
text-decoration: none;
}
a:hover {
color: var(--focused);
}
button {
color: var(--text-color-inverted);
background-color: var(--unfocused);
text-decoration: none;
border: none;
}
button:hover {
color: var(--text-color);
background-color: var(--focused);
}
.content_container {
}
.login {
zoom: 150%;
position: absolute;
top: 35%;
left: 50%;
transform: translate(-50%, -50%);
width: 40%;
}
.login h1 {
font-size: 30px;
text-align: center;
margin-top: -20px;
margin-bottom: 1%;
}
.login img {
position: relative;
left: 50%;
transform: translateX(-50%);
}
.login form {
width: 100%;
text-align: center;
}
.login input {
text-align: left;
font-size: 15px;
background-color: var(--background-color);
border: none;
border-bottom: 2px solid var(--unfocused);
transition: border-bottom 0.2s ease-out;
}
.login input:focus {
outline: none;
border-bottom: 2px solid var(--focused);
}
.login input:required {
border-bottom: 2px solid var(--focused);
}
.login input[required]:invalid {
border-bottom: 2px solid var(--unfocused);
}
.login input[type=text] {
background-image: url("/assets/img/id-card-negated.png");
background-position: 5% center;
background-repeat: no-repeat;
background-size: 15px 15px;
text-indent: 15%;
}
.login input[type=password] {
background-image: url("/assets/img/key-negated.png");
background-position: 5% center;
background-repeat: no-repeat;
background-size: 15px 15px;
text-indent: 15%;
}
.login input[type=submit] {
text-align: center;
width: 30%;
background-color: var(--background-color);
transition: border-bottom 0.2s ease-out;
}
.login input[type=submit]:hover {
border-bottom: 2px solid var(--focused);
}
.side_by_side {
display: flex;
justify-content: center;
}
.error {
text-align: center;
}
.error h1 {
font-size: 300%;
}
.error h2 {
font-size: 200%;
}
.error p {
font-size: 150%;
font-weight: bold;
}
.navbar {
position: sticky;
top: 0;
width: 100%;
z-index: 1000;
}
.navbar ul {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: var(--menu-bg);
}
.navbar li {
float: left;
border-right: 1px solid var(--menu-border);
}
.navbar li:first-child {
border-right: none;
}
.navbar li:last-child {
float: right;
border-right: none;
}
.navbar img {
object-fit: contain;
width: 80px;
margin: auto;
}
.navbar a {
display: block;
padding: 8px;
font-size: 130%;
text-align: center;
color: var(--text-color-inverted);
background-color: var(--unfocused);
}
.navbar a:hover {
color: var(--text-color);
background-color: var(--focused);
}
.usercard {
border-radius: 10px;
border: 3px solid var(--unfocused);
}
.usercard img {
display: block;
margin-top: 2%;
margin-bottom: 2%;
margin-left: auto;
margin-right: auto;
border-radius: 50%;
max-width: 70%;
}
.usercard h1 {
margin-top: 0%;
text-align: center;
font-size: 150%;
background-color: var(--unfocused);
color: var(--text-color-inverted);
}
.usercard p {
font-size: 90%;
font-weight: 700;
}
.chart {
width: 50%;
}
.button_row {
text-align: left;
padding-top: 1%;
padding-bottom: 1%;
}
.button_row button {
font-size: 100%;
margin-left: 5%;
width: 15%;
border-radius: 4px;
}

0
assets/fonts/.gitignore vendored Normal file
View File

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.

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,18 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg fill="#E0E1DD" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="128px" height="128px" viewBox="0 0 893.4 893.4" xml:space="preserve"
>
<g>
<path d="M747.3,0H146.101c-13.8,0-25,11.2-25,25v700.5H234c30.3,0,55,24.7,55,55v112.9H747.3c13.801,0,25-11.2,25-25V25
C772.3,11.2,761.101,0,747.3,0z M636.901,655.6H256.5c-13.8,0-25-11.199-25-25c0-13.8,11.2-25,25-25h380.401
c13.799,0,25,11.2,25,25C661.901,644.4,650.7,655.6,636.901,655.6z M636.901,543.5H256.5c-13.8,0-25-11.2-25-25s11.2-25,25-25
h380.401c13.799,0,25,11.2,25,25S650.7,543.5,636.901,543.5z M661.901,406.4c0,13.8-11.201,25-25,25H256.5c-13.8,0-25-11.2-25-25
l0,0c0-13.801,11.2-25,25-25h380.401C650.7,381.4,661.901,392.6,661.901,406.4L661.901,406.4z M661.901,98.3
c0,12.5-10.102,22.6-22.602,22.6l-97.6,1v55.7l81.201-1c12.5,0,22.6,10.1,22.6,22.6l0,0c0,12.5-10.1,22.6-22.6,22.6l-81.201,1v82
c0,12.5-10.1,22.6-22.6,22.6h-8.1c-12.5,0-22.6-10.1-22.6-22.6V98.3c0-12.5,10.1-22.6,22.6-22.6H639.3
C651.8,75.7,661.901,85.8,661.901,98.3L661.901,98.3z"/>
<path d="M234,755.5h-110.9h-2L259,893.4v-0.7V780.5C259,766.7,247.801,755.5,234,755.5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

BIN
assets/img/icon/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
assets/img/id-card.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
assets/img/key-negated.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
assets/img/key.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
assets/img/learnlytics.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -0,0 +1,28 @@
<svg
width="300" height="150" viewBox="0 0 300 150"
xmlns="http://www.w3.org/2000/svg"
fill="none" stroke-linecap="round" stroke-linejoin="round"
>
<!-- Centering Group -->
<g transform="translate(25, 0)">
<!-- Bar Chart -->
<rect x="0" y="90" width="30" height="30" fill="#2EC4B6" />
<rect x="45" y="60" width="30" height="60" fill="#2EC4B6" />
<rect x="90" y="80" width="30" height="40" fill="#2EC4B6" />
<rect x="135" y="40" width="30" height="80" fill="#2EC4B6" />
<rect x="180" y="70" width="30" height="50" fill="#2EC4B6" />
<rect x="225" y="30" width="30" height="90" fill="#2EC4B6" />
<!-- Analytics Chart - Dynamic Graph Lines -->
<polyline points="15,90 60,60 105,80 150,40 195,70 240,30" stroke="#F4A261" stroke-width="3" stroke-dasharray="8 4" />
<circle cx="15" cy="90" r="5" fill="#F4A261" />
<circle cx="60" cy="60" r="5" fill="#F4A261" />
<circle cx="105" cy="80" r="5" fill="#F4A261" />
<circle cx="150" cy="40" r="5" fill="#F4A261" />
<circle cx="195" cy="70" r="5" fill="#F4A261" />
<circle cx="240" cy="30" r="5" fill="#F4A261" />
<!-- Centered Text -->
<!-- text x="75" y="140" fill="#E0E1DD" font="lato-regular" font-size="20" font-weight="bold">Learnlytics</text-->
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

4
assets/img/smiley-x.svg Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#E0E1DD" width="128px" height="128px" viewBox="0 0 256 256" id="Flat" xmlns="http://www.w3.org/2000/svg">
<path d="M128,28A100,100,0,1,0,228,128,100.11332,100.11332,0,0,0,128,28Zm0,192a92,92,0,1,1,92-92A92.10416,92.10416,0,0,1,128,220ZM186.82812,98.82812,173.65674,112l13.17138,13.17188a3.99957,3.99957,0,1,1-5.65624,5.65624L168,117.65674l-13.17188,13.17138a3.99957,3.99957,0,0,1-5.65624-5.65624L162.34326,112,149.17188,98.82812a3.99957,3.99957,0,0,1,5.65624-5.65624L168,106.34326l13.17188-13.17138a3.99957,3.99957,0,1,1,5.65624,5.65624Zm-80,0L93.65674,112l13.17138,13.17188a3.99957,3.99957,0,1,1-5.65624,5.65624L88,117.65674,74.82812,130.82812a3.99957,3.99957,0,0,1-5.65624-5.65624L82.34326,112,69.17188,98.82812a3.99957,3.99957,0,0,1,5.65624-5.65624L88,106.34326l13.17188-13.17138a3.99957,3.99957,0,0,1,5.65624,5.65624ZM136,180a8,8,0,1,1-8-8A8.00917,8.00917,0,0,1,136,180Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1017 B

BIN
assets/img/user.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

20
assets/js/chart.js Normal file

File diff suppressed because one or more lines are too long

293
assets/js/chartUtils.js Normal file
View File

@@ -0,0 +1,293 @@
function barChart(id, data, labels, tooltip, title, scale_label_x, scale_label_y) {
const canvas = document.getElementById('bar_chart'+id)
const ctx = canvas.getContext("2d");
data = data.map((item) => DecimalPrecision.round(item, 2));
// Gradient
var gradient = ctx.createLinearGradient(0, 0, 0, 500);
gradient.addColorStop(0, '#f4a260');
gradient.addColorStop(1, '#2ec4b6');
// Data
var displayData = {
labels: labels,
datasets: [
{
label: tooltip,
data: data,
backgroundColor: gradient,
}
]
};
// Options
var options = {
responsive: true,
scales: {
x: {
display: true,
text: scale_label_x,
},
y: {
display: true,
text: scale_label_y,
beginAtZero: true
}
},
plugins: {
title: {
display: true,
text: title,
font: {
size: 20,
}
}
},
};
var config = {
type: 'bar',
data: displayData,
options: options
};
new Chart(ctx, config);
}
function barLineChart(id, data, labels, tooltip, title, scale_label_x, scale_label_y) {
const canvas = document.getElementById('bar_line_chart'+id)
const ctx = canvas.getContext("2d");
// Gradient
const gradient = ctx.createLinearGradient(0, 0, 0, 500);
gradient.addColorStop(0, '#f4a260');
gradient.addColorStop(1, '#2ec4b6');
const sum = data.reduce((partialSum, a) => partialSum + a, 0);
const percentage = data.map((item) => DecimalPrecision.round(item/sum*100, 2));
var percentageTick = 100;
var percentageTickSize = 20;
// Data
const displayData = {
labels: labels,
datasets: [
{
label: "Percentage",
data: percentage,
borderColor: '#E0E1DD',
backgroundColor: '#2ec4b6',
yAxisID: 'y1',
type: 'line',
},
{
label: tooltip,
data: data,
backgroundColor: gradient,
yAxisID: 'y',
},
]
};
// Options
const options = {
responsive: true,
scales: {
x: {
display: true,
text: scale_label_x,
},
y: {
display: true,
text: scale_label_y,
beginAtZero: true,
max: Math.max.apply(null, data) + 1,
},
y1: {
display: true,
position: 'right',
beginAtZero: true,
max: percentageTick,
ticks: {
stepSize: percentageTickSize,
},
},
},
plugins: {
title: {
display: true,
text: title,
font: {
size: 20,
}
}
},
};
const config = {
type: 'bar',
data: displayData,
options: options
};
let barlinechart = new Chart(ctx, config);
// Actions
const actions = [
{
name: "Toggle Tick",
handler(chart) {
if (percentageTick == 100 ) {
percentageTick = Math.trunc(Math.max.apply(null, percentage) + 1);
percentageTickSize = Math.trunc(percentageTick / 5);
}
else {
percentageTick = 100;
percentageTickSize = 20;
}
barlinechart.options.scales.y1.max = percentageTick;
barlinechart.options.scales.y1.ticks.stepSize = percentageTickSize;
chart.update();
}
}
];
actions.forEach((a, i) => {
let button = document.createElement("button");
button.id = "button"+i;
button.innerText = a.name;
button.onclick = () => a.handler(barlinechart);
document.querySelector(".button_row").appendChild(button);
});
}
function pieChart(id, data, labels, tooltip, title, scale_label_x, scale_label_y) {
const canvas = document.getElementById('pie_chart'+id)
const ctx = canvas.getContext("2d");
// Data
var displayData = {
labels: labels,
datasets: [
{
label: tooltip,
data: data,
backgroundColor: [
'#f4a260',
'#e77f7a',
'#be6d8e',
'#856490',
'#4f597b',
'#2f4858',
],
}
]
};
// Options
var options = {
responsive: true,
};
var config = {
type: 'pie',
data: displayData,
options: options
};
new Chart(ctx, config);
}
function doughnutChart(id, data, labels, tooltip, title, scale_label_x, scale_label_y) {
const canvas = document.getElementById('doughnut_chart'+id)
const ctx = canvas.getContext("2d");
// Data
var displayData = {
labels: labels,
datasets: [
{
label: tooltip,
data: data,
backgroundColor: [
'#f4a260',
'#e77f7a',
'#be6d8e',
'#856490',
'#4f597b',
'#2f4858',
],
}
]
};
// Options
var options = {
responsive: true,
};
var config = {
type: 'doughnut',
data: displayData,
options: options
};
new Chart(ctx, config);
}
function polarChart(id, data, labels, tooltip, title, scale_label_x, scale_label_y) {
const canvas = document.getElementById('polar_chart'+id)
const ctx = canvas.getContext("2d");
// Data
var displayData = {
labels: labels,
datasets: [
{
label: tooltip,
data: data,
backgroundColor: [
'#f4a260',
'#e77f7a',
'#be6d8e',
'#856490',
'#4f597b',
'#2f4858',
],
}
]
};
// Options
var options = {
responsive: true,
scales: {
x: {
border: { display: true },
grid: {
display: false,
drawOnChartArea: true,
drawTicks: false,
},
},
},
};
var config = {
type: 'polarArea',
data: displayData,
options: config,
};
new Chart(ctx, config);
}

1
assets/js/htmx.min.js vendored Normal file

File diff suppressed because one or more lines are too long

39
assets/js/utils.js Normal file
View File

@@ -0,0 +1,39 @@
var DecimalPrecision = (function() {
if (Math.trunc === undefined) {
Math.trunc = function(v) {
return v < 0 ? Math.ceil(v) : Math.floor(v);
};
}
var decimalAdjust = function myself(type, num, decimalPlaces) {
if (type === 'round' && num < 0)
return -myself(type, -num, decimalPlaces);
var shift = function(value, exponent) {
value = (value + 'e').split('e');
return +(value[0] + 'e' + (+value[1] + (exponent || 0)));
};
var n = shift(num, +decimalPlaces);
return shift(Math[type](n), -decimalPlaces);
};
return {
// Decimal round (half away from zero)
round: function(num, decimalPlaces) {
return decimalAdjust('round', num, decimalPlaces);
},
// Decimal ceil
ceil: function(num, decimalPlaces) {
return decimalAdjust('ceil', num, decimalPlaces);
},
// Decimal floor
floor: function(num, decimalPlaces) {
return decimalAdjust('floor', num, decimalPlaces);
},
// Decimal trunc
trunc: function(num, decimalPlaces) {
return decimalAdjust('trunc', num, decimalPlaces);
},
// Format using fixed-point notation
toFixed: function(num, decimalPlaces) {
return decimalAdjust('round', num, decimalPlaces).toFixed(decimalPlaces);
}
};
})();

BIN
assets/learnlytics.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB