This commit is contained in:
Frieder Hannenheim 2025-01-29 18:09:52 +01:00
parent d8eaa98e36
commit 154f04c202
7 changed files with 190 additions and 17 deletions

View file

@ -13,6 +13,7 @@
just just
toml2json toml2json
nodePackages.webpack-cli nodePackages.webpack-cli
entr
typescript typescript
typescript-language-server typescript-language-server

View file

@ -4,15 +4,21 @@ alias c := clean
build: build:
mkdir -p build mkdir -p build
cat src/data/* | toml2json > build/gewichtungen.json cat ./src/studiengänge/* | toml2json > build/studiengaenge.json
# typescript compilation depends on gewichtungen.json # typescript compilation depends on gewichtungen.json
tsc tsc
mv src/rechner.js build/ mv src/rechner.js build/
# This makes the code more debuggable which is a win in my book
webpack --mode development webpack --mode development
cp src/index.html dist/index.html cp src/index.html src/stylesheet.css dist/
cp ./res/Exo2-VariableFont_wght.ttf dist/
watch:
find src/ | entr -s 'just build'
clean: clean:
rm -rf ./build ./dist rm -rf ./build ./dist
rm ./src/rechner.js

Binary file not shown.

View file

@ -21,18 +21,26 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<head> <head>
<title>iFSR Notenrechner</title> <title>iFSR Notenrechner</title>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="stylesheet.css">
</head> </head>
<body> <body>
<h1>Notenberechnungen</h1> <h1>Notenberechnungen</h1>
<p>Hier könnt ihr Vordiploms- und Abschlussnoten ausgewählter Studiengänge der Fakultät Informatik der TU Dresden berechnen.</p> <p>Hier könnt ihr Vordiploms- und Abschlussnoten ausgewählter Studiengänge der Fakultät Informatik der TU Dresden berechnen.</p>
<label for="options">Wähle eine Berechnung aus</label> <div id="notenform">
<select id="options"> <label for="studiengaenge">Wähle einen Studiengang aus</label>
<option disabled selected value> -- -- </option> <div class="select">
<select id="studiengaenge">
<option disabled selected value> -- </option>
</select> </select>
<span class="focus"></span>
</div>
<div> <form>
<form id="noten"></form> <div id="noten"></div>
</form>
</div> </div>
<script src="rechner.js"></script> <script src="rechner.js"></script>

View file

@ -14,14 +14,14 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import gewichtungen from '../build/gewichtungen.json' import studiengaenge from '../build/studiengaenge.json'
var select = document.getElementById("options") as HTMLSelectElement; var select = document.getElementById("studiengaenge") as HTMLSelectElement;
for (let key in gewichtungen) { for (let key in studiengaenge) {
let option = document.createElement('option'); let option = document.createElement('option');
option.value = key; option.value = key;
option.text = String(gewichtungen[key as keyof typeof gewichtungen].display_name); option.text = String(studiengaenge[key as keyof typeof studiengaenge].display_name);
select.add(option); select.add(option);
} }
select.selectedIndex = 0; select.selectedIndex = 0;
@ -30,10 +30,11 @@ var noten = document.getElementById("noten") as HTMLFormElement;
select.onchange = function changed() { select.onchange = function changed() {
noten.innerHTML = ""; noten.innerHTML = "";
let gewichtung_index = select.selectedOptions[0].value as keyof typeof gewichtungen; let gewichtung_index = select.selectedOptions[0].value as keyof typeof studiengaenge;
let gewichtung = gewichtungen[gewichtung_index]; let gewichtung = studiengaenge[gewichtung_index];
let table = document.createElement('table'); let table = document.createElement('table');
for (let modulIndex in gewichtung.module) { for (let modulIndex in gewichtung.module) {
let modul = gewichtung.module[modulIndex]; let modul = gewichtung.module[modulIndex];
let label = document.createElement('label'); let label = document.createElement('label');
@ -46,7 +47,6 @@ select.onchange = function changed() {
input.required = true; input.required = true;
input.min = "1"; input.min = "1";
input.max = "5"; input.max = "5";
input.style.width = "70px";
input.step = "0.1"; input.step = "0.1";
input.addEventListener("input", () => { input.addEventListener("input", () => {
// Validate with the built-in constraints // Validate with the built-in constraints
@ -60,6 +60,7 @@ select.onchange = function changed() {
input.setCustomValidity("Keine Berechnung möglich bei nicht bestandenen Prüfungen (mit > 4.0)") input.setCustomValidity("Keine Berechnung möglich bei nicht bestandenen Prüfungen (mit > 4.0)")
} }
}); });
input.className = "noteninput";
label.htmlFor = input.id; label.htmlFor = input.id;
label.textContent = modul.name; label.textContent = modul.name;
@ -69,9 +70,9 @@ select.onchange = function changed() {
} }
noten.appendChild(table); noten.appendChild(table);
let submit = document.createElement('button'); let submit = document.createElement('input');
submit.type = "submit"; submit.type = "submit";
submit.innerText = "Berechnen"; submit.value = "Berechnen";
let result = document.createElement('p'); let result = document.createElement('p');

157
src/stylesheet.css Normal file
View file

@ -0,0 +1,157 @@
@font-face {
font-family: "Exo 2";
src: url(./Exo2-VariableFont_wght.ttf) format("truetype");
}
:root {
--base1: rgb(40, 43, 40);
--base2: rgb(60, 63, 60);
--base3: rgb(137, 141, 137);
--base4: rgb(215, 220, 215);
--base5: rgb(235, 240, 235);
--accent1: rgb(177, 255, 28);
--accent2: rgb(156, 214, 24);
--signal: rgb(225, 177, 28);
--gray: rgb(137, 141, 137);
--text: var(--base1);
--bg: var(--base5);
--border: var(--base2);
}
@media (prefers-color-scheme: dark) {
:root {
--text: var(--base5);
--bg: var(--base1);
--border: var(--base3);
};
}
html * {
font-family: "Exo 2", sans-serif;
background-color: var(--bg);
color: var(--text);
}
h1 {
font-size: 24pt;
font-weight: bolder;
}
#notenform {
align-items: center;
display: flex;
flex-direction: column;
}
table {
border-collapse: collapse;
margin: 8px 0;
width: fill;
max-width: 1200px;
}
th, td {
border-top: 1px dotted black;
border-bottom: 1px dotted black;
padding: 8px 0;
}
input {
outline: none;
padding: 4px;
border: 2px solid var(--border);
}
input:focus {
border: 2px solid var(--accent1);
}
#noten {
display: flex;
flex-direction: column;
}
input[type=submit] {
align-self: end;
margin: 8px;
width: 76px;
box-sizing: border-box;
}
label {
margin: 8px;
}
.noteninput {
margin: 0 8px;
border-radius: 2px;
width: 70px;
}
/* remove the spin buttons */
input::-webkit-inner-spin-button,
input::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type=number] {
-moz-appearance: textfield;
}
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background-color: transparent;
border: none;
padding: 4px;
width: 100%;
font-family: inherit;
font-size: inherit;
cursor: inherit;
line-height: inherit;
z-index: 1;
outline: none;
}
select::-ms-expand {
display: none;
}
.select {
display: grid;
grid-template-areas: "select";
align-items: center;
position: relative;
min-width: 15ch;
max-width: 30ch;
border: 1px solid var(--border);
border-radius: 2px;
cursor: pointer;
}
.select select, .select::after {
grid-area: select;
}
.select::after {
content: "";
justify-self: end;
width: 0.8em;
height: 0.5em;
margin-right: 4px;
background-color: var(--accent1);
-webkit-clip-path: polygon(100% 0%, 0 0%, 50% 100%);
clip-path: polygon(100% 0%, 0 0%, 50% 100%);
}
select:focus + .focus {
position: absolute;
top: -1px;
left: -1px;
right: -1px;
bottom: -1px;
border: 2px solid var(--accent1);
border-radius: inherit;
}