feat(ui): release v1.2.0 with improved installer UX, build tests, and docs update

This commit is contained in:
2026-02-16 21:01:38 +01:00
parent efdb50083e
commit bab54fdf2d
10 changed files with 287 additions and 134 deletions

View File

@@ -1,15 +1,17 @@
# Kantine Wrapper Bookmarklet (v1.7.0) # Kantine Wrapper Bookmarklet (v1.2.0)
Ein intelligentes Bookmarklet für die Mitarbeiter-Kantine der Bessa App. Dieses Skript erweitert die Standardansicht um eine **Wochenübersicht**, Kostenkontrolle und verbesserte Usability. Ein intelligentes Bookmarklet für die Mitarbeiter-Kantine der Bessa App. Dieses Skript erweitert die Standardansicht um eine **Wochenübersicht**, Kostenkontrolle und verbesserte Usability.
## 🚀 Features ## 🚀 Features
* **Wochenübersicht:** Zeigt alle Tage der aktuellen Woche auf einen Blick. * **Wochenübersicht:** Zeigt alle Tage der aktuellen Woche auf einen Blick.
* **Bestell-Countdown:** ⏳ Roter Alarm 1h vor Bestellschluss.
* **Smart Highlights:** 🌟 Markiere deine Favoriten (z.B. "Schnitzel", "Vegetarisch").
* **Bestellstatus:** Farbige Indikatoren für bestellte Menüs. * **Bestellstatus:** Farbige Indikatoren für bestellte Menüs.
* **Kostenkontrolle:** Summiert automatisch den Gesamtpreis der Woche. * **Kostenkontrolle:** Summiert automatisch den Gesamtpreis der Woche.
* **Session Reuse:** Nutzt automatisch eine bestehende Login-Session (Loggt dich automatisch ein). * **Session Reuse:** Nutzt automatisch eine bestehende Login-Session (Loggt dich automatisch ein).
* **API Fallback:** Prüft die Verbindung und bietet bei Fehlern einen Direktlink zur Originalseite.
* **Menu Badges:** Zeigt Menü-Codes (M1, M2+) direkt im Header. * **Menu Badges:** Zeigt Menü-Codes (M1, M2+) direkt im Header.
* **Changelog:** Übersicht über neue Funktionen direkt im Installer.
## 📦 Installation ## 📦 Installation

View File

@@ -108,30 +108,33 @@ cat > "$DIST_DIR/install.html" << INSTALLEOF
</head> </head>
<body> <body>
<h1>🍽️ Kantine Wrapper <span style="font-size:0.5em; opacity:0.6; font-weight:400; vertical-align:middle; margin-left:10px;">$VERSION</span></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="card">
<h2>Changelog</h2> <!-- 1. BUTTON (Top Priority) -->
<div class="changelog-container"> <div class="card" style="text-align: center; border: 2px solid #029AA8;">
<!-- CHANGELOG_PLACEHOLDER --> <p style="margin-bottom:15px; font-weight:bold;">👇 Diesen Button in die Lesezeichen-Leiste ziehen:</p>
</div> <p><a class="bookmarklet" id="bookmarklet-link" href="#">⏳ Wird generiert...</a></p>
</div> </div>
<!-- 2. INSTRUCTIONS -->
<div class="card"> <div class="card">
<h2>So funktioniert's</h2> <h2>So funktioniert's</h2>
<ol> <ol>
<li>Ziehe den Button unten in deine <strong>Lesezeichen-Leiste</strong> (Drag & Drop)</li> <li>Ziehe den Button oben 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>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 $VERSION</code></li> <li>Klicke auf das Lesezeichen <code>Kantine $VERSION</code></li>
</ol> </ol>
</div> </div>
<!-- 3. FEATURES -->
<div class="card"> <div class="card">
<h2>✨ Features</h2> <h2>✨ Features</h2>
<ul> <ul>
<li>📅 <strong>Wochenübersicht:</strong> Die ganze Woche auf einen Blick.</li> <li>📅 <strong>Wochenübersicht:</strong> Die ganze Woche auf einen Blick.</li>
<li>⏳ <strong>Order Countdown:</strong> Roter Alarm 1h vor Bestellschluss.</li>
<li>🌟 <strong>Smart Highlights:</strong> Markiere deine Favoriten (z.B. "Schnitzel").</li>
<li>💰 <strong>Kostenkontrolle:</strong> Automatische Berechnung der Wochensumme.</li> <li>💰 <strong>Kostenkontrolle:</strong> Automatische Berechnung der Wochensumme.</li>
<li>🔑 <strong>Auto-Login:</strong> Nutzt deine bestehende Session.</li> <li>🔑 <strong>Auto-Login:</strong> Nutzt deine bestehende Session.</li>
<li>🏷️ <strong>Badges & Status:</strong> Menü-Codes (M1, M2) und Bestellstatus direkt sichtbar.</li> <li>🏷️ <strong>Badges & Status:</strong> Menü-Codes (M1, M2) und Bestellstatus direkt sichtbar.</li>
<li>🛡️ <strong>Offline-Support:</strong> Speichert Menüdaten lokal.</li>
</ul> </ul>
<div style="margin-top: 30px; padding: 15px; background: rgba(233, 69, 96, 0.1); border: 1px solid rgba(233, 69, 96, 0.3); border-radius: 8px; font-size: 0.85em; color: #ddd;"> <div style="margin-top: 30px; padding: 15px; background: rgba(233, 69, 96, 0.1); border: 1px solid rgba(233, 69, 96, 0.3); border-radius: 8px; font-size: 0.85em; color: #ddd;">
@@ -139,8 +142,15 @@ cat > "$DIST_DIR/install.html" << INSTALLEOF
Die Verwendung dieses Bookmarklets erfolgt auf eigene Verantwortung. Der Entwickler übernimmt keine Haftung für Schäden, Datenverlust oder ungewollte Bestellungen, die durch die Nutzung dieser Software entstehen. Die Verwendung dieses Bookmarklets erfolgt auf eigene Verantwortung. Der Entwickler übernimmt keine Haftung für Schäden, Datenverlust oder ungewollte Bestellungen, die durch die Nutzung dieser Software entstehen.
</div> </div>
</div> </div>
<p>👇 Diesen Button in die Lesezeichen-Leiste ziehen:</p>
<p><a class="bookmarklet" id="bookmarklet-link" href="#">⏳ Wird generiert...</a></p> <!-- 4. CHANGELOG (Bottom) -->
<div class="card">
<h2>Changelog</h2>
<div class="changelog-container">
<!-- CHANGELOG_PLACEHOLDER -->
</div>
</div>
<script> <script>
INSTALLEOF INSTALLEOF
@@ -168,27 +178,22 @@ import sys, json, urllib.parse
# 1. Read JS and Replace VERSION # 1. Read JS and Replace VERSION
js_template = sys.stdin.read() js_template = sys.stdin.read()
# We do replacement here in Python to be safe
js = js_template.replace('{{VERSION}}', '$VERSION') js = js_template.replace('{{VERSION}}', '$VERSION')
# 2. Prepare CSS # 2. Prepare CSS for injection via createElement('style')
css = open('$CSS_FILE').read().replace('\n', ' ').replace(' ', ' ') css = open('$CSS_FILE').read().replace('\n', ' ').replace(' ', ' ')
escaped_css = css.replace('\\\\', '\\\\\\\\').replace(\"'\", \"\\\\'\").replace('\"', '\\\\\"') escaped_css = css.replace('\\\\', '\\\\\\\\').replace(\"'\", \"\\\\'\").replace('\"', '\\\\\"')
# 3. Inject CSS and Update URL # 3. Update URL
update_url = 'https://htmlpreview.github.io/?https://github.com/TauNeutrino/kantine-overview/blob/main/dist/install.html' update_url = 'https://htmlpreview.github.io/?https://github.com/TauNeutrino/kantine-overview/blob/main/dist/install.html'
js = js.replace('https://github.com/TauNeutrino/kantine-overview/raw/main/dist/install.html', update_url) js = js.replace('https://github.com/TauNeutrino/kantine-overview/raw/main/dist/install.html', update_url)
js = js.replace('{{CSS_ESCAPED}}', escaped_css)
# 4. Create Bookmarklet Code # 4. Create Bookmarklet Code with CSS injection
# Wrap in IIFE # Inject CSS via style element (same pattern as bookmarklet-payload.js)
bookmarklet_code = 'javascript:(function(){' + js + '})();' css_injection = \"var s=document.createElement('style');s.textContent='\" + escaped_css + \"';document.head.appendChild(s);\"
bookmarklet_code = 'javascript:(function(){' + css_injection + js + '})();'
# 5. URL Encode the body (keeping javascript: prefix) # 5. URL Encode
# We accept that simple encoding is better.
# But browsers expect encoded URI for href.
# However, for bookmarklet usage, user drags the link.
# If we encode everything, it's safer.
encoded_code = urllib.parse.quote(bookmarklet_code, safe=':/()!;=+,') encoded_code = urllib.parse.quote(bookmarklet_code, safe=':/()!;=+,')
# Output as JSON string for the HTML script to assign to href # Output as JSON string for the HTML script to assign to href
@@ -218,3 +223,14 @@ echo ""
echo "=== Build Complete ===" echo "=== Build Complete ==="
echo "Files in $DIST_DIR:" echo "Files in $DIST_DIR:"
ls -la "$DIST_DIR/" ls -la "$DIST_DIR/"
# === 4. Run build-time tests ===
echo ""
echo "=== Running Build Tests ==="
python3 "$SCRIPT_DIR/test_build.py"
TEST_EXIT=$?
if [ $TEST_EXIT -ne 0 ]; then
echo "❌ Build tests FAILED! See above for details."
exit 1
fi
echo "✅ All build tests passed."

View File

@@ -1,3 +1,8 @@
## v1.2.0 (2026-02-16)
- **Feature**: Bessere UX im Installer (Button oben, Log unten, Features aktualisiert). 💅
- **Tech**: Build-Tests hinzugefügt. 🧪
- **Fix**: Encoding-Probleme final behoben (dank Python Buildlogic). 🐍
## v1.1.2 (2026-02-16) ## v1.1.2 (2026-02-16)
- **Fix**: Encoding-Problem beim Bookmarklet behoben (URL Malformed Error). 🔗 - **Fix**: Encoding-Problem beim Bookmarklet behoben (URL Malformed Error). 🔗

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

78
dist/install.html vendored

File diff suppressed because one or more lines are too long

View File

@@ -152,17 +152,6 @@ body {
justify-content: center; justify-content: center;
} }
.weekly-cost {
white-space: nowrap;
font-size: 0.9rem;
font-weight: 600;
color: var(--success-color);
background-color: var(--bg-body);
padding: 0.25rem 0.75rem;
border-radius: 20px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
border: 1px solid var(--border-color);
}
.header-week-title { .header-week-title {
font-size: 1.1rem; font-size: 1.1rem;
@@ -1177,13 +1166,15 @@ body {
color: var(--text-primary); color: var(--text-primary);
/* Ensure text remains standard color */ /* Ensure text remains standard color */
} }
/* Update Icon */ /* Update Icon */
.update-icon { .update-icon {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin-left: 8px; margin-left: 8px;
background-color: rgba(16, 185, 129, 0.2); /* Green tint */ background-color: rgba(16, 185, 129, 0.2);
/* Green tint */
color: var(--success-color); color: var(--success-color);
border-radius: 50%; border-radius: 50%;
width: 24px; width: 24px;
@@ -1202,9 +1193,17 @@ body {
} }
@keyframes pulse { @keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4); } 0% {
70% { box-shadow: 0 0 0 6px rgba(16, 185, 129, 0); } box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4);
100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); } }
70% {
box-shadow: 0 0 0 6px rgba(16, 185, 129, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(16, 185, 129, 0);
}
} }
/* Order Countdown */ /* Order Countdown */
@@ -1235,14 +1234,23 @@ body {
} }
@keyframes pulse-red { @keyframes pulse-red {
0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); } 0% {
70% { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); } box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4);
100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } }
70% {
box-shadow: 0 0 0 6px rgba(239, 68, 68, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(239, 68, 68, 0);
}
} }
/* Smart Highlights */ /* Smart Highlights */
.highlight-glow { .highlight-glow {
box-shadow: 0 0 15px rgba(59, 130, 246, 0.5); /* Blue glow */ box-shadow: 0 0 15px rgba(59, 130, 246, 0.5);
/* Blue glow */
border: 1px solid rgba(59, 130, 246, 0.8); border: 1px solid rgba(59, 130, 246, 0.8);
background: rgba(59, 130, 246, 0.05); background: rgba(59, 130, 246, 0.05);
position: relative; position: relative;
@@ -1251,14 +1259,16 @@ body {
/* Nav Badge with Count */ /* Nav Badge with Count */
.nav-badge.has-highlights { .nav-badge.has-highlights {
background-color: var(--card-bg); /* Neutral background */ background-color: var(--bg-card);
/* Neutral background */
color: var(--text-primary); color: var(--text-primary);
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
padding: 2px 6px; padding: 2px 6px;
} }
.nav-badge .highlight-count { .nav-badge .highlight-count {
color: #3b82f6; /* Blue 500 */ color: #3b82f6;
/* Blue 500 */
font-weight: 700; font-weight: 700;
margin-left: 4px; margin-left: 4px;
} }
@@ -1304,7 +1314,7 @@ body {
.input-group input { .input-group input {
flex: 1; flex: 1;
padding: 0.75rem; padding: 0.75rem;
background: var(--bg-color); background: var(--bg-body);
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
color: var(--text-primary); color: var(--text-primary);
border-radius: 8px; border-radius: 8px;
@@ -1313,7 +1323,7 @@ body {
/* Update Banner Enhanced */ /* Update Banner Enhanced */
.change-summary { .change-summary {
font-size: 0.8rem; font-size: 0.8rem;
background: rgba(0,0,0,0.1); background: rgba(0, 0, 0, 0.1);
padding: 0.5rem; padding: 0.5rem;
border-radius: 4px; border-radius: 4px;
margin: 0.5rem 0; margin: 0.5rem 0;
@@ -1323,6 +1333,7 @@ body {
max-height: 100px; max-height: 100px;
overflow-y: auto; overflow-y: auto;
} }
.update-content { .update-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -1335,17 +1346,18 @@ body {
padding-left: 1.5rem; padding-left: 1.5rem;
margin: 0.5rem 0; margin: 0.5rem 0;
} }
.changelog-container li { .changelog-container li {
margin-bottom: 0.4rem; margin-bottom: 0.4rem;
line-height: 1.5; line-height: 1.5;
} }
.changelog-container h3 { .changelog-container h3 {
margin-top: 1.5rem; margin-top: 1.5rem;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
font-size: 1.1em; font-size: 1.1em;
color: var(--accent-color); color: var(--accent-color);
} } </style>
</style>
</head> </head>
<body> <body>
<script> <script>
@@ -1417,7 +1429,7 @@ body {
<div class="brand"> <div class="brand">
<span class="material-icons-round logo-icon">restaurant_menu</span> <span class="material-icons-round logo-icon">restaurant_menu</span>
<div class="header-left"> <div class="header-left">
<h1>Kantinen Übersicht <small style="font-size: 0.6em; opacity: 0.7; font-weight: 400;">v1.1.2</small></h1> <h1>Kantinen Übersicht <small style="font-size: 0.6em; opacity: 0.7; font-weight: 400;">v1.2.0</small></h1>
<div id="last-updated-subtitle" class="subtitle"></div> <div id="last-updated-subtitle" class="subtitle"></div>
</div> </div>
</div> </div>
@@ -2750,7 +2762,7 @@ body {
// === Version Check === // === Version Check ===
async function checkForUpdates() { async function checkForUpdates() {
const CurrentVersion = 'v1.1.2'; const CurrentVersion = 'v1.2.0';
const VersionUrl = 'https://raw.githubusercontent.com/TauNeutrino/kantine-overview/main/version.txt'; const VersionUrl = 'https://raw.githubusercontent.com/TauNeutrino/kantine-overview/main/version.txt';
const InstallerUrl = 'https://htmlpreview.github.io/?https://github.com/TauNeutrino/kantine-overview/blob/main/dist/install.html'; const InstallerUrl = 'https://htmlpreview.github.io/?https://github.com/TauNeutrino/kantine-overview/blob/main/dist/install.html';

View File

@@ -141,17 +141,6 @@ body {
justify-content: center; justify-content: center;
} }
.weekly-cost {
white-space: nowrap;
font-size: 0.9rem;
font-weight: 600;
color: var(--success-color);
background-color: var(--bg-body);
padding: 0.25rem 0.75rem;
border-radius: 20px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
border: 1px solid var(--border-color);
}
.header-week-title { .header-week-title {
font-size: 1.1rem; font-size: 1.1rem;
@@ -1166,13 +1155,15 @@ body {
color: var(--text-primary); color: var(--text-primary);
/* Ensure text remains standard color */ /* Ensure text remains standard color */
} }
/* Update Icon */ /* Update Icon */
.update-icon { .update-icon {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin-left: 8px; margin-left: 8px;
background-color: rgba(16, 185, 129, 0.2); /* Green tint */ background-color: rgba(16, 185, 129, 0.2);
/* Green tint */
color: var(--success-color); color: var(--success-color);
border-radius: 50%; border-radius: 50%;
width: 24px; width: 24px;
@@ -1191,9 +1182,17 @@ body {
} }
@keyframes pulse { @keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4); } 0% {
70% { box-shadow: 0 0 0 6px rgba(16, 185, 129, 0); } box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4);
100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); } }
70% {
box-shadow: 0 0 0 6px rgba(16, 185, 129, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(16, 185, 129, 0);
}
} }
/* Order Countdown */ /* Order Countdown */
@@ -1224,14 +1223,23 @@ body {
} }
@keyframes pulse-red { @keyframes pulse-red {
0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); } 0% {
70% { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); } box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4);
100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } }
70% {
box-shadow: 0 0 0 6px rgba(239, 68, 68, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(239, 68, 68, 0);
}
} }
/* Smart Highlights */ /* Smart Highlights */
.highlight-glow { .highlight-glow {
box-shadow: 0 0 15px rgba(59, 130, 246, 0.5); /* Blue glow */ box-shadow: 0 0 15px rgba(59, 130, 246, 0.5);
/* Blue glow */
border: 1px solid rgba(59, 130, 246, 0.8); border: 1px solid rgba(59, 130, 246, 0.8);
background: rgba(59, 130, 246, 0.05); background: rgba(59, 130, 246, 0.05);
position: relative; position: relative;
@@ -1240,14 +1248,16 @@ body {
/* Nav Badge with Count */ /* Nav Badge with Count */
.nav-badge.has-highlights { .nav-badge.has-highlights {
background-color: var(--card-bg); /* Neutral background */ background-color: var(--bg-card);
/* Neutral background */
color: var(--text-primary); color: var(--text-primary);
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
padding: 2px 6px; padding: 2px 6px;
} }
.nav-badge .highlight-count { .nav-badge .highlight-count {
color: #3b82f6; /* Blue 500 */ color: #3b82f6;
/* Blue 500 */
font-weight: 700; font-weight: 700;
margin-left: 4px; margin-left: 4px;
} }
@@ -1293,7 +1303,7 @@ body {
.input-group input { .input-group input {
flex: 1; flex: 1;
padding: 0.75rem; padding: 0.75rem;
background: var(--bg-color); background: var(--bg-body);
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
color: var(--text-primary); color: var(--text-primary);
border-radius: 8px; border-radius: 8px;
@@ -1302,7 +1312,7 @@ body {
/* Update Banner Enhanced */ /* Update Banner Enhanced */
.change-summary { .change-summary {
font-size: 0.8rem; font-size: 0.8rem;
background: rgba(0,0,0,0.1); background: rgba(0, 0, 0, 0.1);
padding: 0.5rem; padding: 0.5rem;
border-radius: 4px; border-radius: 4px;
margin: 0.5rem 0; margin: 0.5rem 0;
@@ -1312,6 +1322,7 @@ body {
max-height: 100px; max-height: 100px;
overflow-y: auto; overflow-y: auto;
} }
.update-content { .update-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -1324,10 +1335,12 @@ body {
padding-left: 1.5rem; padding-left: 1.5rem;
margin: 0.5rem 0; margin: 0.5rem 0;
} }
.changelog-container li { .changelog-container li {
margin-bottom: 0.4rem; margin-bottom: 0.4rem;
line-height: 1.5; line-height: 1.5;
} }
.changelog-container h3 { .changelog-container h3 {
margin-top: 1.5rem; margin-top: 1.5rem;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;

89
test_build.py Executable file
View File

@@ -0,0 +1,89 @@
import os
import sys
DIST_DIR = os.path.join(os.path.dirname(__file__), 'dist')
INSTALL_HTML = os.path.join(DIST_DIR, 'install.html')
BOOKMARKLET_TXT = os.path.join(DIST_DIR, 'bookmarklet.txt')
STANDALONE_HTML = os.path.join(DIST_DIR, 'kantine-standalone.html')
def check_file_exists(path, description):
if not os.path.exists(path):
print(f"❌ MISSING: {description} ({path})")
return False
# Check if not empty
if os.path.getsize(path) == 0:
print(f"❌ EMPTY: {description} ({path})")
return False
print(f"✅ FOUND: {description}")
return True
def check_content(path, must_contain=[], must_not_contain=[]):
with open(path, 'r', encoding='utf-8') as f:
content = f.read()
success = True
for item in must_contain:
if item not in content:
print(f"❌ MISSING CONTENT: '{item}' in {os.path.basename(path)}")
success = False
for item in must_not_contain:
if item in content:
print(f"❌ FORBIDDEN CONTENT: '{item}' in {os.path.basename(path)}")
success = False
if success:
print(f"✅ CONTENT VERIFIED: {os.path.basename(path)}")
return success
def main():
print("=== Running Build Tests ===")
# 1. Existence Check
if not all([
check_file_exists(INSTALL_HTML, "Installer HTML"),
check_file_exists(BOOKMARKLET_TXT, "Bookmarklet Text"),
check_file_exists(STANDALONE_HTML, "Standalone HTML")
]):
sys.exit(1)
# 2. Bookmarklet Logic Check
# Must have the CSS injection fix from the external AI
# Must have correct versioning
# Must be properly URL encoded (checking for common issues)
# Read bookmarklet code (decoded mostly by being in txt? No, txt is usually the raw URL)
with open(BOOKMARKLET_TXT, 'r') as f:
bm_code = f.read().strip()
if not bm_code.startswith("javascript:"):
print("❌ Bookmarklet does not start with 'javascript:'")
sys.exit(1)
# Check for placeholder leftovers
if not check_content(BOOKMARKLET_TXT,
must_contain=["document.createElement('style')", "M1", "M2"],
must_not_contain=["{{VERSION}}", "{{CSS_ESCAPED}}"]):
sys.exit(1)
# Check for CSS injection specific logic
if "document.head.appendChild(s)" not in bm_code and "appendChild(s)" not in bm_code: # URL encoded might mask this, strictly checking decoded would be better but simple check first
# Actually bm_code is URL encoded. We should decode it to verify logic.
import urllib.parse
decoded = urllib.parse.unquote(bm_code)
if "document.createElement('style')" not in decoded:
print("❌ CSS Injection logic missing in bookmarklet")
sys.exit(1)
print("✅ CSS Injection logic confirmed")
# 3. Installer Check
if not check_content(INSTALL_HTML,
must_contain=["Kantine Wrapper", "So funktioniert's", "changelog-container"],
must_not_contain=["CHANGELOG_HTML_PLACEHOLDER"]): # If we used that
sys.exit(1)
print("🎉 ALL TESTS PASSED")
sys.exit(0)
if __name__ == "__main__":
main()

View File

@@ -1 +1 @@
v1.1.2 v1.2.0