add slide content improvements and dev server setup
223015b: - add WTF hex code explanation slide (89=137 decimal, PNG signature) - add ASCII lead slide with historical context - remove Hilbert-Studie reference from title 223015c termin 2: - add OSI layer 5 (session) and layer 6 (presentation) slides - add URL/domain anatomy slide - mark HTTP/S section as klausur - improve status codes formatting with client/server examples - add CRUD column to HTTP methods table infrastructure: - add dev-server.sh for multi-course development - update generate-index.sh with course-specific colors - add QR codes for slide URLs
This commit is contained in:
106
scripts/dev-server.sh
Executable file
106
scripts/dev-server.sh
Executable file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env bash
|
||||
# Development server script for HdM slides
|
||||
# Starts index server + marp servers for each course
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
INDEX_PORT=1310
|
||||
COURSE_B_PORT=1311
|
||||
COURSE_C_PORT=1312
|
||||
COURSE_DIR="courses"
|
||||
DEV_INDEX_DIR=".dev-index"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
echo -e "\n${RED}Shutting down servers...${NC}"
|
||||
kill $PID_INDEX $PID_B $PID_C 2>/dev/null || true
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Kill existing processes on our ports
|
||||
kill_existing() {
|
||||
echo -e "${BLUE}Cleaning up existing processes...${NC}"
|
||||
# Kill marp processes first
|
||||
pkill -9 -f "marp-cli" 2>/dev/null || true
|
||||
pkill -f "python3 -m http.server" 2>/dev/null || true
|
||||
# Kill ports including marp's WebSocket ports (37717-37720 range)
|
||||
fuser -k $INDEX_PORT/tcp $COURSE_B_PORT/tcp $COURSE_C_PORT/tcp 2>/dev/null || true
|
||||
fuser -k 37717/tcp 37718/tcp 37719/tcp 37720/tcp 2>/dev/null || true
|
||||
sleep 2
|
||||
}
|
||||
|
||||
# Generate dev index
|
||||
generate_index() {
|
||||
mkdir -p "$DEV_INDEX_DIR"
|
||||
cat > "$DEV_INDEX_DIR/index.html" << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>HdM Slides - Dev</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,"SF Pro Display","Segoe UI",Roboto,sans-serif;max-width:720px;margin:0 auto;padding:3rem 1.5rem;background:#fafafa;color:#1d1d1f;line-height:1.5}
|
||||
h1{font-size:2rem;font-weight:600;letter-spacing:-0.02em;margin-bottom:.5rem}
|
||||
.subtitle{color:#86868b;font-size:1rem}
|
||||
.courses{margin-top:2rem;display:flex;flex-direction:column;gap:.75rem}
|
||||
a.course{display:block;background:#fff;border-radius:12px;padding:1.5rem;text-decoration:none;color:inherit;box-shadow:0 1px 3px rgba(0,0,0,0.08);transition:all .2s ease;cursor:pointer}
|
||||
a.course:hover{transform:translateY(-2px);box-shadow:0 4px 12px rgba(0,0,0,0.12)}
|
||||
.course-label{font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em}
|
||||
.course-b .course-label{color:#5da9e9}
|
||||
.course-c .course-label{color:#d63384}
|
||||
.course-title{font-size:1.15rem;font-weight:500;color:#1d1d1f;margin:.25rem 0}
|
||||
.course-info{font-size:.85rem;color:#86868b}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>HdM Slides</h1>
|
||||
<p class="subtitle">Development Server</p>
|
||||
<div class="courses">
|
||||
EOF
|
||||
echo " <a class=\"course course-b\" href=\"http://localhost:$COURSE_B_PORT\"><span class=\"course-label\">223015b</span><div class=\"course-title\">Dateiformate, Schnittstellen, Speichermedien & Distributionswege</div><span class=\"course-info\">Port $COURSE_B_PORT</span></a>" >> "$DEV_INDEX_DIR/index.html"
|
||||
echo " <a class=\"course course-c\" href=\"http://localhost:$COURSE_C_PORT\"><span class=\"course-label\">223015c</span><div class=\"course-title\">Grundlagen IT- und Internettechnik</div><span class=\"course-info\">Port $COURSE_C_PORT</span></a>" >> "$DEV_INDEX_DIR/index.html"
|
||||
cat >> "$DEV_INDEX_DIR/index.html" << 'EOF'
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
}
|
||||
|
||||
# Main
|
||||
trap cleanup SIGINT SIGTERM
|
||||
|
||||
kill_existing
|
||||
generate_index
|
||||
|
||||
echo -e "${GREEN}Starting development servers...${NC}"
|
||||
echo ""
|
||||
echo -e " Index: ${BLUE}http://localhost:$INDEX_PORT${NC}"
|
||||
echo -e " 223015b: ${BLUE}http://localhost:$COURSE_B_PORT${NC}"
|
||||
echo -e " 223015c: ${BLUE}http://localhost:$COURSE_C_PORT${NC}"
|
||||
echo ""
|
||||
echo -e "Press ${RED}Ctrl+C${NC} to stop all servers"
|
||||
echo ""
|
||||
|
||||
# Start servers
|
||||
python3 -m http.server $INDEX_PORT --directory "$DEV_INDEX_DIR" &
|
||||
PID_INDEX=$!
|
||||
|
||||
PORT=$COURSE_B_PORT npx @marp-team/marp-cli --server "$COURSE_DIR/223015b/slides/" &
|
||||
PID_B=$!
|
||||
|
||||
sleep 3 # Stagger starts to avoid WebSocket port collision
|
||||
|
||||
PORT=$COURSE_C_PORT npx @marp-team/marp-cli --server "$COURSE_DIR/223015c/slides/" &
|
||||
PID_C=$!
|
||||
|
||||
# Wait for any process to exit
|
||||
wait
|
||||
@@ -8,22 +8,40 @@ BUILD_DIR="${2:-build/$COURSE}"
|
||||
# Course-specific configuration
|
||||
case "$COURSE" in
|
||||
223015b)
|
||||
TITLE="223015b - Dateiformate, Schnittstellen, Speichermedien"
|
||||
SUBTITLE="Dateiformate, Schnittstellen, Speichermedien & Distributionswege"
|
||||
REPO_URL="https://git.librete.ch/hdm/223015b"
|
||||
TITLE="Dateiformate, Schnittstellen, Speichermedien & Distributionswege"
|
||||
SUBTITLE="223015b · Modul \"Technik 1\" · 1. Semester"
|
||||
SLIDES_URL="https://librete.ch/hdm/223015b"
|
||||
ACCENT_COLOR="#5da9e9"
|
||||
ACCENT_LIGHT="#e8f4fc"
|
||||
;;
|
||||
223015c)
|
||||
TITLE="223015c - Internettechnologien"
|
||||
SUBTITLE="Internettechnologien"
|
||||
REPO_URL="https://git.librete.ch/hdm/223015c"
|
||||
TITLE="Grundlagen IT- und Internettechnik"
|
||||
SUBTITLE="223015c · Modul \"Technik 1\" · 1. Semester"
|
||||
SLIDES_URL="https://librete.ch/hdm/223015c"
|
||||
ACCENT_COLOR="#d63384"
|
||||
ACCENT_LIGHT="#fce4ec"
|
||||
;;
|
||||
*)
|
||||
TITLE="$COURSE - HdM Slides"
|
||||
SUBTITLE="Lecture Slides"
|
||||
REPO_URL="https://git.librete.ch/hdm/$COURSE"
|
||||
SLIDES_URL="https://librete.ch/hdm/$COURSE"
|
||||
ACCENT_COLOR="#0066cc"
|
||||
ACCENT_LIGHT="#e8f4fc"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Topic mappings for nice German titles
|
||||
declare -A TOPIC_MAP
|
||||
TOPIC_MAP["intro"]="Einführung"
|
||||
TOPIC_MAP["grundlagen-text-audio"]="Grundlagen, Text & Audio"
|
||||
TOPIC_MAP["bild-audio-video"]="Bild, Audio & Video"
|
||||
TOPIC_MAP["speichermedien-schnittstellen"]="Speichermedien & Schnittstellen"
|
||||
TOPIC_MAP["distribution-apis-zukunft"]="Distribution, APIs & Zukunft"
|
||||
TOPIC_MAP["vertiefung-offene-fragen"]="Vertiefung & Offene Fragen"
|
||||
TOPIC_MAP["geschichte-grundlagen-html"]="Geschichte, Grundlagen & HTML"
|
||||
TOPIC_MAP["netzwerke-protokolle-css"]="Netzwerke, Protokolle & CSS"
|
||||
TOPIC_MAP["interaktivitaet-javascript"]="Interaktivität & JavaScript"
|
||||
|
||||
cat > "$BUILD_DIR/index.html" << HEADER
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
@@ -32,65 +50,142 @@ cat > "$BUILD_DIR/index.html" << HEADER
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>$TITLE</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; }
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
max-width: 800px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", Roboto, sans-serif;
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
background: #1a1a2e;
|
||||
color: #eee;
|
||||
padding: 3rem 1.5rem;
|
||||
background: #fafafa;
|
||||
color: #1d1d1f;
|
||||
line-height: 1.5;
|
||||
}
|
||||
h1 { color: #fff; margin-bottom: 0.5rem; }
|
||||
.subtitle { color: #888; margin-bottom: 2rem; }
|
||||
.termin-row {
|
||||
header { margin-bottom: 2rem; }
|
||||
h1 {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.02em;
|
||||
margin-bottom: 0.5rem;
|
||||
color: $ACCENT_COLOR;
|
||||
}
|
||||
.subtitle {
|
||||
color: #86868b;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
.meta {
|
||||
color: #86868b;
|
||||
font-size: 0.875rem;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
.termine {
|
||||
margin-top: 1.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
.termin-card {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
|
||||
transition: all 0.2s ease;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.termin {
|
||||
background: #16213e;
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
text-decoration: none;
|
||||
.termin-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.12);
|
||||
}
|
||||
.termin-link {
|
||||
display: block;
|
||||
flex: 1;
|
||||
transition: transform 0.2s, background 0.2s;
|
||||
}
|
||||
.termin:hover { background: #1f4068; transform: translateX(5px); }
|
||||
.termin h2 { color: #fff; margin: 0 0 0.5rem 0; font-size: 1.2rem; }
|
||||
.termin .date { color: #4ecca3; font-size: 0.9rem; }
|
||||
.termin .topic { color: #aaa; font-size: 0.95rem; margin-left: 1rem; }
|
||||
.pdf {
|
||||
background: #e94560;
|
||||
color: #fff;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 4px;
|
||||
padding: 1.25rem 1.5rem;
|
||||
text-decoration: none;
|
||||
font-size: 0.85rem;
|
||||
color: inherit;
|
||||
grid-column: 1;
|
||||
}
|
||||
.termin-label {
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
color: $ACCENT_COLOR;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
.termin-title {
|
||||
font-size: 1.05rem;
|
||||
font-weight: 500;
|
||||
transition: background 0.2s;
|
||||
color: #1d1d1f;
|
||||
margin: 0.15rem 0;
|
||||
}
|
||||
.pdf:hover { background: #ff6b6b; }
|
||||
.qr-section {
|
||||
margin-top: 2rem;
|
||||
text-align: center;
|
||||
.termin-date {
|
||||
font-size: 0.8rem;
|
||||
color: #86868b;
|
||||
}
|
||||
.qr-section img {
|
||||
max-width: 150px;
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
padding: 0.5rem;
|
||||
text-decoration: none;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.btn-slides {
|
||||
background: $ACCENT_COLOR;
|
||||
color: #fff;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
.btn-slides:hover {
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
.btn-pdf {
|
||||
background: #f5f5f7;
|
||||
color: #1d1d1f;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
.btn-pdf:hover { background: #e8e8ed; }
|
||||
/* Make entire card clickable via overlay */
|
||||
.termin-link::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 12px;
|
||||
}
|
||||
footer {
|
||||
margin-top: 2.5rem;
|
||||
padding-top: 1.5rem;
|
||||
border-top: 1px solid #e5e5e7;
|
||||
color: #86868b;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
footer a { color: $ACCENT_COLOR; text-decoration: none; }
|
||||
footer a:hover { text-decoration: underline; }
|
||||
@media (max-width: 600px) {
|
||||
.termin-card {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.termin-link {
|
||||
padding-bottom: 0.75rem;
|
||||
}
|
||||
.btn-slides, .btn-pdf {
|
||||
margin: 0 1rem 1rem 1.5rem;
|
||||
}
|
||||
}
|
||||
footer { margin-top: 2rem; color: #666; font-size: 0.85rem; text-align: center; }
|
||||
footer a { color: #4ecca3; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>$COURSE</h1>
|
||||
<p class="subtitle">$SUBTITLE<br>
|
||||
HdM Stuttgart - WS 2025/26 - Michael Czechowski</p>
|
||||
<header>
|
||||
<h1>$TITLE</h1>
|
||||
<p class="subtitle">$SUBTITLE</p>
|
||||
<p class="meta">HdM Stuttgart · Wintersemester 2025/26 · Michael Czechowski</p>
|
||||
</header>
|
||||
<div class="termine">
|
||||
HEADER
|
||||
|
||||
# Generate links for each termin (sorted)
|
||||
@@ -98,23 +193,26 @@ for html in $(ls "$BUILD_DIR"/2*.html 2>/dev/null | sort); do
|
||||
filename=$(basename "$html")
|
||||
|
||||
# Extract components from filename
|
||||
date=$(echo "$filename" | grep -oE '^[0-9]{4}-[0-9]{2}-[0-9]{2}')
|
||||
date=$(echo "$filename" | grep -oE '^[0-9]{4}-[0-9x]{2}-[0-9x]{2}')
|
||||
termin_num=$(echo "$filename" | grep -oE 'termin-[0-9]+' | grep -oE '[0-9]+')
|
||||
topic_raw=$(echo "$filename" | sed -E 's/^[0-9]{4}-[0-9]{2}-[0-9]{2}-termin-[0-9]+-//' | sed 's/\.html$//')
|
||||
topic_raw=$(echo "$filename" | sed -E 's/^[0-9]{4}-[0-9x]{2}-[0-9x]{2}-termin-[0-9]+-//' | sed 's/\.html$//')
|
||||
|
||||
# Format topic: replace - with space, capitalize
|
||||
topic=$(echo "$topic_raw" | sed 's/-/ /g' | sed 's/.*/\u&/')
|
||||
# Look up nice topic name or fallback
|
||||
topic="${TOPIC_MAP[$topic_raw]}"
|
||||
if [[ -z "$topic" ]]; then
|
||||
topic=$(echo "$topic_raw" | sed 's/-/ /g' | sed 's/.*/\u&/')
|
||||
fi
|
||||
|
||||
# Format date
|
||||
if [[ "$date" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
|
||||
formatted_date=$(date -d "$date" "+%d.%m.%Y" 2>/dev/null || echo "$date")
|
||||
if [[ "$date" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] && [[ ! "$date" =~ xx ]]; then
|
||||
formatted_date=$(date -d "$date" "+%d. %B %Y" 2>/dev/null || echo "$date")
|
||||
else
|
||||
formatted_date="TBA"
|
||||
formatted_date="Termin folgt"
|
||||
fi
|
||||
|
||||
# Handle termin number
|
||||
if [[ "$termin_num" == "0" ]]; then
|
||||
termin_label="Einfuhrung"
|
||||
termin_label="Einführung"
|
||||
else
|
||||
termin_label="Termin $termin_num"
|
||||
fi
|
||||
@@ -124,35 +222,27 @@ for html in $(ls "$BUILD_DIR"/2*.html 2>/dev/null | sort); do
|
||||
# Check if PDF exists
|
||||
pdf_link=""
|
||||
if [[ -f "$BUILD_DIR/$pdf_filename" ]]; then
|
||||
pdf_link="<a href=\"$pdf_filename\" class=\"pdf\">PDF</a>"
|
||||
pdf_link="<a href=\"$pdf_filename\" class=\"btn btn-pdf\">PDF</a>"
|
||||
fi
|
||||
|
||||
cat >> "$BUILD_DIR/index.html" << LINK
|
||||
<div class="termin-row">
|
||||
<a href="$filename" class="termin">
|
||||
<h2>$termin_label</h2>
|
||||
<span class="date">$formatted_date</span>
|
||||
<span class="topic">$topic</span>
|
||||
</a>
|
||||
$pdf_link
|
||||
</div>
|
||||
<div class="termin-card">
|
||||
<a href="$filename" class="termin-link">
|
||||
<div class="termin-label">$termin_label</div>
|
||||
<div class="termin-title">$topic</div>
|
||||
<div class="termin-date">$formatted_date</div>
|
||||
</a>
|
||||
<a href="$filename" class="btn btn-slides">Folien</a>
|
||||
$pdf_link
|
||||
</div>
|
||||
LINK
|
||||
done
|
||||
|
||||
# Add QR code if exists
|
||||
if [[ -f "$BUILD_DIR/qr-$COURSE.png" ]]; then
|
||||
cat >> "$BUILD_DIR/index.html" << QRSECTION
|
||||
<div class="qr-section">
|
||||
<img src="qr-$COURSE.png" alt="QR Code">
|
||||
<p style="color: #888; font-size: 0.8rem;">Scan to open on mobile</p>
|
||||
</div>
|
||||
QRSECTION
|
||||
fi
|
||||
|
||||
cat >> "$BUILD_DIR/index.html" << FOOTER
|
||||
</div>
|
||||
<footer>
|
||||
<a href="$REPO_URL">Git Repository</a> -
|
||||
<a href="mailto:mail@librete.ch">Kontakt</a>
|
||||
<a href="mailto:mail@librete.ch">Kontakt</a> ·
|
||||
<a href="../">Alle Kurse</a>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user