add skedul
All checks were successful
Swaous.Asuscomm Build / Build-Docker-Image (push) Successful in 27s

This commit is contained in:
2025-02-06 08:42:34 -05:00
parent af8b8de11d
commit 423b8f6b39
5 changed files with 305 additions and 0 deletions

1
skedul/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
data.json

36
skedul/README Normal file
View File

@@ -0,0 +1,36 @@
very simple customized class schedules applet. to use it, create a data.json file in the project root and put all the files in the static directory of your webserver!
features
* shows first, next, and last classes for the day
* shows all your classes for the week on a grid
* configure links for class buildings (google maps or whatever)
data.json is structured like so:
{
"year": 2025,
"semester": "Semester", // spring, fall, whatever
"credits": 30, // your class credits this semester [purely cosmetic]
"maps": {
"building name": "link to the building in google maps or whatever"
},
"week": [
{
"days": [1, 3, 5], // 1 is monday, 2 is tuesday, etc. weekend courses currently aren't supported.
"start_time": 1100, // 24-hour timestamps.
"end_time": 1215,
"name": "Physics",
"type": "Lecture", // options are Lecture, Lab, Studio, Class, and Test.
"building": "The Bestest Building", // must be exactly the same as the building name in `maps` for the links to work
"room": "101" // your room in the building
},
{
"days": [2, 4],
"start_time": 1230,
"end_time": 1515,
"name": "Chemistry",
"type": "Lab",
"building": "Laboratorium!",
"room": "66"
}
]
}

43
skedul/index.html Normal file
View File

@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<title>Tyler's Course Schedule</title>
<link rel="stylesheet" href="main.css" />
<meta name="viewport" content="width=device-width,initial-scale=1"
</head>
<body>
<div id="topline">
<div>
<span id="semester"></span> <span id="year"></span>
<p style="font-size: 0.7em; color: lightgrey;"><span id="credits"></span> credits</p>
</div>
<div id="firstclass">
<b>FIRST CLASS</b><br>
<a class="bloc"><span class="cname"></span> <span class="ctype"></span> at <span class="building"></span> <span class="room"></span> from <span class="start"></span> to <span class="end"></span></a>
</div>
<div id="nextclass">
<b>NEXT CLASS</b><br>
<a class="bloc"><span class="cname"></span> <span class="ctype"></span> at <span class="building"></span> <span class="room"></span> from <span class="start"></span> to <span class="end"></span></a>
</div>
<div id="lastclass">
<b>LAST CLASS</b><br>
<a class="bloc"><span class="cname"></span> <span class="ctype"></span> at <span class="building"></span> <span class="room"></span> from <span class="start"></span> to <span class="end"></span></a>
</div>
</div>
<table id="schedule">
<thead>
<tr>
<td></td>
<td>Monday</td>
<td>Tuesday</td>
<td>Wednesday</td>
<td>Thursday</td>
<td>Friday</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script src="main.js"></script>
</body>
</html>

121
skedul/main.css Normal file
View File

@@ -0,0 +1,121 @@
#topline {
padding: 10px;
background-color: rgb(0, 51, 68);
color: white;
font-family: monospace;
display: flex;
}
#topline > * {
margin-left: 20px;
margin-right: 20px;
}
#topline a {
color: white;
}
#firstclass {
margin-left: auto;
}
#schedule>tbody td:first-child {
font-size: 0.7em;
color: transparent;
position: relative;
padding-right: 20px;
}
td:first-child>span {
position: absolute;
top: -0.7em;
left: 0px;
background-color: white;
width: auto;
color: black;
}
thead td {
font-weight: bold;
text-align: center;
}
td:not(:first-child) {
width: 20%;
}
table {
border-collapse: collapse;
width: auto;
}
tr {
border-top: 1px solid rgb(167, 167, 167);
position: relative;
height: 1.1em;
}
.coursename {
font-weight: bold;
display: block;
text-align: center;
font-size: 1.1em;
}
.coursetype {
font-weight: bold;
}
td:not(:first-child) {
vertical-align: top;
font-family: monospace;
padding: 4px;
position: relative;
}
td.Lecture {
background-color: rgb(255, 207, 255);
}
td.Lab {
background-color: lightblue;
}
td.Class {
background-color: yellow;
}
td.Studio {
background-color: lightgreen;
}
td.Test {
background-color: red;
box-shadow: 0px 0px 20px 10px rgb(88, 0, 0);
}
.youarehere {
color: white;
background-color: black;
text-align: center;
}
.youarehere::after{
font-weight: bold;
content: 'you are HERE!';
}
@media (max-width:1000px) {
td {
font-size: 0.5em !important;
}
#topline {
flex-direction: column;
}
#topline > * {
margin: 20px !important;
}
tr {
height: 0.7em;
}
}

104
skedul/main.js Normal file
View File

@@ -0,0 +1,104 @@
function tohours(mns) { // convert a value in minutes to a 24-hour timestamp, e.g. 330 -> 0530
let hour = Math.floor(mns / 60);
let minute = mns % 60;
return hour * 100 + minute;
}
function tomins(hrs) { // convert a value in 24-hour to minutes, the inverse of tohours
let hour = Math.floor(hrs / 100);
let minute = hrs % 100;
return hour * 60 + minute;
}
const daystart = tomins(1000);
function zpad(thing, zeroes) { // left-pad a string with zeroes
thing = "" + thing;
while (thing.length < zeroes) {
thing = "0" + thing;
}
return thing;
}
function tonicehrs(hrs) { // convert a value in 24-hour to a string (800 -> "08:00", 1645 -> "16:45")
let hour = Math.floor(hrs / 100);
if (hour > 12) {
hour -= 12;
}
let minute = hrs % 100;
return zpad(hour, 2) + ":" + zpad(minute, 2);
}
function tablesetup() {
for (var i = 0; i < 11 * 4; i ++) {
let row = document.createElement("tr");
let time = tonicehrs(tohours(daystart + i * 15))
row.innerHTML = `<td>${time}<span>${time}</span></td><td></td><td></td><td></td><td></td><td></td>`;
document.querySelector("#schedule > tbody").appendChild(row);
}
}
function setClassTo(el, c, map) {
el.querySelector(".cname").innerText = c.name;
el.querySelector(".ctype").innerText = c.type;
el.querySelector(".bloc").href = map[c.building];
el.querySelector(".building").innerText = c.building;
el.querySelector(".room").innerText = c.room;
el.querySelector(".start").innerText = tonicehrs(c.start_time);
el.querySelector(".end").innerText = tonicehrs(c.end_time);
}
window.addEventListener("load", async () => {
let data = await (await fetch("data.json")).json();
document.getElementById("year").innerHTML = data.year;
document.getElementById("semester").innerHTML = data.semester;
document.getElementById("credits").innerHTML = data.credits;
tablesetup();
let tbody = document.querySelector("#schedule > tbody")
let curday = new Date().getDay();
let firstClass = undefined;
let nextClass = undefined;
let lastClass = undefined;
let now = new Date();
let curTime = now.getMinutes() + now.getHours() * 100;
let curTimeSnap = Math.round((tomins(curTime) - daystart) / 15);
tbody.children[curTimeSnap].children[curday].classList.add("youarehere");
for (let cls of data.week) {
for (let day of cls.days) {
if (day == curday) {
if (firstClass == undefined || cls.start_time < firstClass.start_time) {
firstClass = cls;
}
if (lastClass == undefined || cls.end_time > lastClass.end_time) {
lastClass = cls;
}
if (cls.start_time > curTime) {
if (nextClass == undefined || cls.start_time < nextClass.start_time) {
nextClass = cls;
}
}
}
let start = Math.floor((tomins(cls.start_time) - daystart) / 15);
let el = tbody.children[start].children[day];
el.classList.add("class");
let rows = Math.floor((tomins(cls.end_time) - tomins(cls.start_time)) / 15);
el.rowSpan = rows;
for (var i = start + 1; i < start + rows; i ++) { // cull the tds that this td is overlapping
tbody.children[i].removeChild(tbody.children[i].children[day]);
}
el.classList.add(cls.type);
el.innerHTML = `<span class="coursename">${cls.name}</span><span class="coursetype">${cls.type}</span> at <a href="${data.maps[cls.building]}" about="blank">${cls.building}</a> ${cls.room}`
}
}
if (firstClass) {
setClassTo(document.getElementById("firstclass"), firstClass, data.maps);
}
if (nextClass) {
setClassTo(document.getElementById("nextclass"), nextClass, data.maps);
}
if (lastClass) {
setClassTo(document.getElementById("lastclass"), lastClass, data.maps);
}
});