Compare commits

...

8 Commits

8 changed files with 193 additions and 30 deletions

View File

@@ -8,19 +8,28 @@ DIST_DIR="$SCRIPT_DIR/dist"
CSS_FILE="$SCRIPT_DIR/style.css"
JS_FILE="$SCRIPT_DIR/kantine.js"
# === VERSION ===
if [ -f "$SCRIPT_DIR/version.txt" ]; then
VERSION=$(cat "$SCRIPT_DIR/version.txt" | tr -d '\n')
else
echo "ERROR: version.txt not found"
exit 1
fi
mkdir -p "$DIST_DIR"
echo "=== Kantine Bookmarklet Builder ==="
echo "=== Kantine Bookmarklet Builder ($VERSION) ==="
# Check files exist
if [ ! -f "$CSS_FILE" ]; then echo "ERROR: $CSS_FILE not found"; exit 1; fi
if [ ! -f "$JS_FILE" ]; then echo "ERROR: $JS_FILE not found"; exit 1; fi
CSS_CONTENT=$(cat "$CSS_FILE")
JS_CONTENT=$(cat "$JS_FILE")
# Inject version into JS
JS_CONTENT=$(cat "$JS_FILE" | sed "s/{{VERSION}}/$VERSION/g")
# === 1. Build standalone HTML (for local testing/dev) ===
cat > "$DIST_DIR/kantine-standalone.html" << 'HTMLEOF'
cat > "$DIST_DIR/kantine-standalone.html" << HTMLEOF
<!DOCTYPE html>
<html lang="de">
<head>
@@ -37,7 +46,7 @@ HTMLEOF
# Inject CSS
cat "$CSS_FILE" >> "$DIST_DIR/kantine-standalone.html"
cat >> "$DIST_DIR/kantine-standalone.html" << 'HTMLEOF'
cat >> "$DIST_DIR/kantine-standalone.html" << HTMLEOF
</style>
</head>
<body>
@@ -45,9 +54,9 @@ cat >> "$DIST_DIR/kantine-standalone.html" << 'HTMLEOF'
HTMLEOF
# Inject JS
cat "$JS_FILE" >> "$DIST_DIR/kantine-standalone.html"
echo "$JS_CONTENT" >> "$DIST_DIR/kantine-standalone.html"
cat >> "$DIST_DIR/kantine-standalone.html" << 'HTMLEOF'
cat >> "$DIST_DIR/kantine-standalone.html" << HTMLEOF
</script>
</body>
</html>
@@ -69,7 +78,7 @@ var s=document.createElement('style');
s.textContent='${CSS_ESCAPED}';
document.head.appendChild(s);
var sc=document.createElement('script');
sc.textContent=$(cat "$JS_FILE" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))" 2>/dev/null || cat "$JS_FILE" | sed 's/\\/\\\\/g' | sed "s/'/\\\\'/g" | sed 's/"/\\\\"/g' | tr '\n' ' ' | sed 's/^/"/' | sed 's/$/"/');
sc.textContent=$(echo "$JS_CONTENT" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))" 2>/dev/null || echo "$JS_CONTENT" | sed 's/\\/\\\\/g' | sed "s/'/\\\\'/g" | sed 's/"/\\\\"/g' | tr '\n' ' ' | sed 's/^/"/' | sed 's/$/"/');
document.head.appendChild(sc);
})();
PAYLOADEOF
@@ -81,15 +90,15 @@ echo "javascript:${BOOKMARKLET_RAW}" > "$DIST_DIR/bookmarklet.txt"
echo "✅ Bookmarklet URL: $DIST_DIR/bookmarklet.txt"
# === 3. Create an easy-to-use HTML installer page ===
cat > "$DIST_DIR/install.html" << 'INSTALLEOF'
cat > "$DIST_DIR/install.html" << INSTALLEOF
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Kantine Wrapper Installer</title>
<title>Kantine Wrapper Installer ($VERSION)</title>
<style>
body { font-family: 'Inter', sans-serif; max-width: 600px; margin: 40px auto; padding: 20px; background: #1a1a2e; color: #eee; }
h1 { color: #029AA8; }
h1 { color: #029AA8; } /* Knapp Teal */
.instructions { background: #16213e; padding: 20px; border-radius: 12px; margin: 20px 0; }
.instructions ol li { margin: 10px 0; }
a.bookmarklet { display: inline-block; background: #029AA8; color: white; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: 600; font-size: 18px; cursor: grab; }
@@ -98,13 +107,13 @@ cat > "$DIST_DIR/install.html" << 'INSTALLEOF'
</style>
</head>
<body>
<h1>🍽️ Kantine Wrapper</h1>
<h1>🍽️ Kantine Wrapper <span style="font-size:0.5em; opacity:0.6; font-weight:400; vertical-align:middle; margin-left:10px;">$VERSION</span></h1>
<div class="instructions">
<h2>Installation</h2>
<ol>
<li>Ziehe den Button unten in deine <strong>Lesezeichen-Leiste</strong> (Drag & Drop)</li>
<li>Navigiere zu <a href="https://web.bessa.app/knapp-kantine" style="color:#029AA8">web.bessa.app/knapp-kantine</a></li>
<li>Klicke auf das Lesezeichen <code>Kantine Wrapper</code></li>
<li>Klicke auf das Lesezeichen <code>Kantine $VERSION</code></li>
</ol>
<h2>✨ Features</h2>
@@ -128,7 +137,7 @@ INSTALLEOF
# Embed the bookmarklet URL inline
echo "document.getElementById('bookmarklet-link').href = " >> "$DIST_DIR/install.html"
cat "$JS_FILE" | python3 -c "
echo "$JS_CONTENT" | python3 -c "
import sys, json
js = sys.stdin.read()
css = open('$CSS_FILE').read().replace('\\n', ' ').replace(' ', ' ')
@@ -136,8 +145,8 @@ bmk = '''javascript:(function(){if(window.__KANTINE_LOADED){alert(\"Already load
print(json.dumps(bmk) + ';')
" 2>/dev/null >> "$DIST_DIR/install.html" || echo "'javascript:alert(\"Build error\")'" >> "$DIST_DIR/install.html"
cat >> "$DIST_DIR/install.html" << 'INSTALLEOF'
document.getElementById('bookmarklet-link').textContent = '🍽️ Kantine Wrapper';
cat >> "$DIST_DIR/install.html" << INSTALLEOF
document.getElementById('bookmarklet-link').textContent = 'Kantine $VERSION';
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

12
dist/install.html vendored

File diff suppressed because one or more lines are too long

View File

@@ -1176,7 +1176,37 @@ body {
font-weight: 700;
color: var(--text-primary);
/* Ensure text remains standard color */
} </style>
}
/* Update Icon */
.update-icon {
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: 8px;
background-color: rgba(16, 185, 129, 0.2); /* Green tint */
color: var(--success-color);
border-radius: 50%;
width: 24px;
height: 24px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
text-decoration: none;
animation: pulse 2s infinite;
}
.update-icon:hover {
background-color: var(--success-color);
color: white;
transform: scale(1.1);
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4); }
70% { box-shadow: 0 0 0 6px rgba(16, 185, 129, 0); }
100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}
</style>
</head>
<body>
<script>
@@ -1247,8 +1277,8 @@ body {
<div class="header-content">
<div class="brand">
<span class="material-icons-round logo-icon">restaurant_menu</span>
<div class="brand-text">
<h1>Kantinen Übersicht</h1>
<div class="header-left">
<h1>Kantinen Übersicht <small style="font-size: 0.6em; opacity: 0.7; font-weight: 400;">v1.0.3</small></h1>
<div id="last-updated-subtitle" class="subtitle"></div>
</div>
</div>
@@ -2454,6 +2484,50 @@ body {
return card;
}
// === Version Check ===
async function checkForUpdates() {
const CurrentVersion = 'v1.0.3'; // Injected by build script
const VersionUrl = 'https://raw.githubusercontent.com/TauNeutrino/kantine-overview/main/version.txt';
// Use htmlpreview.github.io to render the HTML directly in browser
const InstallerUrl = 'https://htmlpreview.github.io/?https://github.com/TauNeutrino/kantine-overview/blob/main/dist/install.html';
console.log(`[Kantine] Checking for updates... (Current: ${CurrentVersion})`);
try {
const response = await fetch(VersionUrl, { cache: 'no-cache' });
if (!response.ok) return;
const remoteVersion = (await response.text()).trim();
console.log(`[Kantine] Remote version: ${remoteVersion}`);
if (remoteVersion && remoteVersion !== CurrentVersion) {
// Simple semantic version check or string inequality
// Assuming format v1.0.0
showUpdateIcon(remoteVersion, InstallerUrl);
}
} catch (error) {
console.warn('[Kantine] Version check failed:', error);
}
}
function showUpdateIcon(newVersion, url) {
const headerTitle = document.querySelector('.header-left h1');
if (!headerTitle) return;
// Check if already added
if (headerTitle.querySelector('.update-icon')) return;
const icon = document.createElement('a');
icon.className = 'update-icon';
icon.href = url;
icon.target = '_blank';
icon.innerHTML = '🆕'; // User requested icon
icon.title = `Neue Version verfügbar (${newVersion}). Klick für download`;
headerTitle.appendChild(icon);
showToast(`Update verfügbar: ${newVersion}`, 'info');
}
// === Helpers ===
function getISOWeek(date) {
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
@@ -2499,6 +2573,9 @@ body {
startPolling();
}
// Check for updates
checkForUpdates();
console.log('Kantine Wrapper loaded ✅');
})();

View File

@@ -65,8 +65,8 @@
<div class="header-content">
<div class="brand">
<span class="material-icons-round logo-icon">restaurant_menu</span>
<div class="brand-text">
<h1>Kantinen Übersicht</h1>
<div class="header-left">
<h1>Kantinen Übersicht <small style="font-size: 0.6em; opacity: 0.7; font-weight: 400;">{{VERSION}}</small></h1>
<div id="last-updated-subtitle" class="subtitle"></div>
</div>
</div>
@@ -1272,6 +1272,50 @@
return card;
}
// === Version Check ===
async function checkForUpdates() {
const CurrentVersion = '{{VERSION}}'; // Injected by build script
const VersionUrl = 'https://raw.githubusercontent.com/TauNeutrino/kantine-overview/main/version.txt';
// Use htmlpreview.github.io to render the HTML directly in browser
const InstallerUrl = 'https://htmlpreview.github.io/?https://github.com/TauNeutrino/kantine-overview/blob/main/dist/install.html';
console.log(`[Kantine] Checking for updates... (Current: ${CurrentVersion})`);
try {
const response = await fetch(VersionUrl, { cache: 'no-cache' });
if (!response.ok) return;
const remoteVersion = (await response.text()).trim();
console.log(`[Kantine] Remote version: ${remoteVersion}`);
if (remoteVersion && remoteVersion !== CurrentVersion) {
// Simple semantic version check or string inequality
// Assuming format v1.0.0
showUpdateIcon(remoteVersion, InstallerUrl);
}
} catch (error) {
console.warn('[Kantine] Version check failed:', error);
}
}
function showUpdateIcon(newVersion, url) {
const headerTitle = document.querySelector('.header-left h1');
if (!headerTitle) return;
// Check if already added
if (headerTitle.querySelector('.update-icon')) return;
const icon = document.createElement('a');
icon.className = 'update-icon';
icon.href = url;
icon.target = '_blank';
icon.innerHTML = '🆕'; // User requested icon
icon.title = `Neue Version verfügbar (${newVersion}). Klick für download`;
headerTitle.appendChild(icon);
showToast(`Update verfügbar: ${newVersion}`, 'info');
}
// === Helpers ===
function getISOWeek(date) {
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
@@ -1317,6 +1361,9 @@
startPolling();
}
// Check for updates
checkForUpdates();
console.log('Kantine Wrapper loaded ✅');
})();

View File

@@ -1165,4 +1165,33 @@ body {
font-weight: 700;
color: var(--text-primary);
/* Ensure text remains standard color */
}
}
/* Update Icon */
.update-icon {
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: 8px;
background-color: rgba(16, 185, 129, 0.2); /* Green tint */
color: var(--success-color);
border-radius: 50%;
width: 24px;
height: 24px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
text-decoration: none;
animation: pulse 2s infinite;
}
.update-icon:hover {
background-color: var(--success-color);
color: white;
transform: scale(1.1);
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4); }
70% { box-shadow: 0 0 0 6px rgba(16, 185, 129, 0); }
100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}

1
version.txt Executable file
View File

@@ -0,0 +1 @@
v1.0.3