Compare commits
17 Commits
1be6e44d7f
...
v1.6.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b8ac5ca1d | ||
|
|
2964eba88b | ||
|
|
089e5375b4 | ||
|
|
e514f42dbe | ||
|
|
f7a9b061ea | ||
|
|
fe75347682 | ||
|
|
5c5255058c | ||
|
|
e16398ef74 | ||
|
|
6a57e2716f | ||
|
|
d383808f4f | ||
|
|
498b400033 | ||
|
|
884a17e7d3 | ||
|
|
ad660799ec | ||
|
|
a5fe50bbf0 | ||
|
|
a98faec51e | ||
|
|
212bf3b015 | ||
|
|
f29ecd4b79 |
@@ -28,13 +28,13 @@ if [ ! -f "$JS_FILE" ]; then echo "ERROR: $JS_FILE not found"; exit 1; fi
|
||||
# Generate favicon.png from favicon_base.png if base exists
|
||||
FAVICON_BASE="$SCRIPT_DIR/favicon_base.png"
|
||||
if [ -f "$FAVICON_BASE" ]; then
|
||||
echo "Generating 32x32 favicon.png from favicon_base.png..."
|
||||
echo "Generating 40x40 favicon.png from favicon_base.png..."
|
||||
python3 -c "
|
||||
import sys
|
||||
from PIL import Image
|
||||
try:
|
||||
img = Image.open('$FAVICON_BASE')
|
||||
img_resized = img.resize((32, 32), Image.Resampling.LANCZOS)
|
||||
img_resized = img.resize((40, 40), Image.Resampling.LANCZOS)
|
||||
img_resized.save('$FAVICON_FILE')
|
||||
except Exception as e:
|
||||
print('Favicon generation error:', e)
|
||||
@@ -99,15 +99,20 @@ echo "✅ Standalone HTML: $DIST_DIR/kantine-standalone.html"
|
||||
# Escape CSS for embedding in JS string
|
||||
CSS_ESCAPED=$(echo "$CSS_CONTENT" | sed "s/'/\\\\'/g" | tr '\n' ' ' | sed 's/ */ /g')
|
||||
|
||||
# Build bookmarklet payload
|
||||
# Create a minified version for the injected bookmarklet payloads
|
||||
echo "Minifying JS with Terser..."
|
||||
TEMP_JS=$(mktemp)
|
||||
echo "$JS_CONTENT" > "$TEMP_JS"
|
||||
JS_MINIFIED=$(npx -y terser "$TEMP_JS" --compress --mangle)
|
||||
rm -f "$TEMP_JS"
|
||||
|
||||
cat > "$DIST_DIR/bookmarklet-payload.js" << PAYLOADEOF
|
||||
(function(){
|
||||
javascript:(function(){
|
||||
if(window.__KANTINE_LOADED){alert('Kantine Wrapper already loaded!');return;}
|
||||
var s=document.createElement('style');
|
||||
s.textContent='${CSS_ESCAPED}';
|
||||
document.head.appendChild(s);
|
||||
var s=document.createElement('style');s.textContent='${CSS_ESCAPED}';document.head.appendChild(s);
|
||||
// Inject JS logic
|
||||
var sc=document.createElement('script');
|
||||
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/$/"/');
|
||||
sc.textContent=$(echo "$JS_MINIFIED" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))" 2>/dev/null || echo "$JS_MINIFIED" | sed 's/\\/\\\\/g' | sed "s/'/\\\\'/g" | sed 's/"/\\\\"/g' | tr '\n' ' ' | sed 's/^/"/' | sed 's/$/"/');
|
||||
document.head.appendChild(sc);
|
||||
})();
|
||||
PAYLOADEOF
|
||||
@@ -161,7 +166,7 @@ cat > "$DIST_DIR/install.html" << INSTALLEOF
|
||||
|
||||
<div style="text-align: center; margin-bottom: 30px;">
|
||||
<h1 style="margin-bottom: 5px; display: flex; align-items: center; justify-content: center; gap: 10px;">
|
||||
<img src="$FAVICON_URL" alt="Logo" style="width: 38px; height: 38px;">
|
||||
<img src="$FAVICON_URL" alt="Logo" style="width: 40px; height: 40px;">
|
||||
Kantine Wrapper
|
||||
<span style="font-size:0.5em; opacity:0.6; font-weight:400; margin-left:5px;">$VERSION</span>
|
||||
</h1>
|
||||
@@ -239,12 +244,11 @@ fi
|
||||
|
||||
# Embed the bookmarklet URL inline
|
||||
echo "document.getElementById('bookmarklet-link').href = " >> "$DIST_DIR/install.html"
|
||||
echo "$JS_CONTENT" | python3 -c "
|
||||
echo "$JS_MINIFIED" | python3 -c "
|
||||
import sys, json, urllib.parse
|
||||
|
||||
# 1. Read JS and Replace VERSION + Favicon
|
||||
js_template = sys.stdin.read()
|
||||
js = js_template.replace('{{VERSION}}', '$VERSION').replace('{{FAVICON_DATA_URI}}', '$FAVICON_URL')
|
||||
js = sys.stdin.read()
|
||||
|
||||
# 2. Prepare CSS for injection via createElement('style')
|
||||
css = open('$CSS_FILE').read().replace('\n', ' ').replace(' ', ' ')
|
||||
@@ -303,26 +307,30 @@ ls -la "$DIST_DIR/"
|
||||
# === 4. Run build-time tests ===
|
||||
echo ""
|
||||
echo "=== Running Logic Tests ==="
|
||||
node "$SCRIPT_DIR/test_logic.js"
|
||||
timeout 15s node "$SCRIPT_DIR/test_logic.js"
|
||||
LOGIC_EXIT=$?
|
||||
if [ $LOGIC_EXIT -ne 0 ]; then
|
||||
echo "❌ Logic tests FAILED! See above for details."
|
||||
echo "❌ Logic tests FAILED or TIMED OUT (Exit: $LOGIC_EXIT)! See above for details."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== Running DOM Interaction Tests ==="
|
||||
node "$SCRIPT_DIR/tests/test_dom.js"
|
||||
timeout 15s node "$SCRIPT_DIR/tests/test_dom.js"
|
||||
DOM_EXIT=$?
|
||||
if [ $DOM_EXIT -ne 0 ]; then
|
||||
echo "❌ DOM UI tests FAILED! Regressions detected."
|
||||
echo "❌ DOM UI tests FAILED or TIMED OUT (Exit: $DOM_EXIT)! Regressions detected."
|
||||
# Ensure playwright processes are killed if they leak
|
||||
pkill -f playwright || true
|
||||
pkill -f "node.*test_dom" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
echo "=== Running Build Tests ==="
|
||||
python3 "$SCRIPT_DIR/test_build.py"
|
||||
timeout 15s python3 "$SCRIPT_DIR/test_build.py"
|
||||
TEST_EXIT=$?
|
||||
if [ $TEST_EXIT -ne 0 ]; then
|
||||
echo "❌ Build tests FAILED! See above for details."
|
||||
echo "❌ Build tests FAILED or TIMED OUT (Exit: $TEST_EXIT)! See above for details."
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ All build tests passed."
|
||||
|
||||
14
changelog.md
14
changelog.md
@@ -1,3 +1,17 @@
|
||||
## v1.6.8 (2026-03-06)
|
||||
- ⚡ **Performance**: Das JavaScript für das Kantinen-Bookmarklet wird nun beim Build-Prozess (via Terser) minimiert, was die Länge der injizierten URL spürbar reduziert.
|
||||
|
||||
## v1.6.7 (2026-03-06)
|
||||
- 🎨 **Style**: Das neue Header-Logo (`favicon_base.png`) wird nun konsequent auf 40x40px generiert und gerendert.
|
||||
|
||||
## v1.6.6 (2026-03-06)
|
||||
- 🎨 **Style**: Den Schatten und den hervorstehenden Karten-Effekt für bestellte Menüs an vergangenen Tagen komplett entfernt - verbleiben nun visuell flach und unaufdringlich wie nicht-bestellte Menüs.
|
||||
|
||||
## v1.6.5 (2026-03-06)
|
||||
- ✨ **Feature**: Das `restaurant_menu` Icon im Header wurde durch das neue `favicon_base.png` Logo ersetzt, passend zur Textgröße skaliert.
|
||||
- 🎨 **Style**: Violette Umrahmung (Bestellt-Markierung) an vergangenen Tagen entfernt, um den Fokus auf aktuelle und zukünftige Bestellungen zu lenken.
|
||||
- 🎨 **Style**: Der Glow-Effekt für am heutigen Tag bestellte Menüs wurde intensiviert.
|
||||
|
||||
## v1.6.4 (2026-03-05)
|
||||
- ✨ **Feature**: Sprach-Lexikon (DE/EN) massiv erweitert um österreichische Begriffe (Nockerl, Fleckerl, Topfen, Mohn, Most etc.) und gängige Tippfehler aus dem Bessa-System (trukey, coffe, oveb etc.).
|
||||
- 🧹 **Cleanup**: Sprach-Lexikon dedupliziert und alphabetisch sortiert für bessere Performance und Wartbarkeit.
|
||||
|
||||
9
dist/bookmarklet-payload.js
vendored
9
dist/bookmarklet-payload.js
vendored
File diff suppressed because one or more lines are too long
2
dist/bookmarklet.txt
vendored
2
dist/bookmarklet.txt
vendored
File diff suppressed because one or more lines are too long
34
dist/install.html
vendored
34
dist/install.html
vendored
File diff suppressed because one or more lines are too long
39
dist/kantine-standalone.html
vendored
39
dist/kantine-standalone.html
vendored
File diff suppressed because one or more lines are too long
BIN
favicon.png
BIN
favicon.png
Binary file not shown.
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 3.6 KiB |
29
favicon.svg
29
favicon.svg
@@ -1,29 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
|
||||
<!-- Fork (left, with gap to triangle) -->
|
||||
<g transform="translate(2, 10)">
|
||||
<!-- Tines -->
|
||||
<rect x="1" y="0" width="1.8" height="16" rx="0.9" fill="#333"/>
|
||||
<rect x="4.6" y="0" width="1.8" height="16" rx="0.9" fill="#333"/>
|
||||
<rect x="8.2" y="0" width="1.8" height="16" rx="0.9" fill="#333"/>
|
||||
<!-- Connector -->
|
||||
<rect x="1" y="14" width="9" height="3.5" rx="1.5" fill="#333"/>
|
||||
<!-- Handle -->
|
||||
<rect x="3.5" y="16.5" width="4" height="24" rx="2" fill="#333"/>
|
||||
</g>
|
||||
|
||||
<!-- Triangle (center, equilateral aspect ratio ~1:0.866) -->
|
||||
<!-- Equilateral: base=28, height=24.25 => keeps proper ratio -->
|
||||
<polygon points="32,8 47,48 17,48" fill="none" stroke="#333" stroke-width="4" stroke-linejoin="round"/>
|
||||
|
||||
<!-- Knife (right, with gap to triangle) -->
|
||||
<g transform="translate(50, 10)">
|
||||
<!-- Blade (slight curve) -->
|
||||
<path d="M3,0 C3,0 3,0 3,0 L3,17 L10,14 C10,6 7,0 3,0 Z" fill="#333"/>
|
||||
<!-- Spine -->
|
||||
<rect x="1.5" y="0" width="2" height="18" rx="1" fill="#333"/>
|
||||
<!-- Bolster -->
|
||||
<rect x="1.5" y="16.5" width="8.5" height="3.5" rx="1.2" fill="#333"/>
|
||||
<!-- Handle -->
|
||||
<rect x="3.5" y="19" width="4" height="22" rx="2" fill="#333"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -80,7 +80,7 @@
|
||||
<header class="app-header">
|
||||
<div class="header-content">
|
||||
<div class="brand">
|
||||
<span class="material-icons-round logo-icon">restaurant_menu</span>
|
||||
<img src="{{FAVICON_DATA_URI}}" alt="Logo" class="logo-img" style="height: 2em; width: 2em; object-fit: contain;">
|
||||
<div class="header-left">
|
||||
<h1>Kantinen Übersicht <small class="version-tag" style="font-size: 0.6em; opacity: 0.7; font-weight: 400; cursor: pointer;" title="Klick für Versionsmenü">{{VERSION}}</small></h1>
|
||||
<div id="last-updated-subtitle" class="subtitle"></div>
|
||||
@@ -268,7 +268,7 @@
|
||||
</main>
|
||||
|
||||
<footer class="app-footer">
|
||||
<p>Jetzt Bessa Einfach! • Knapp-Kantine Wrapper • <span id="current-year">${new Date().getFullYear()}</span> by Kaufis-Kitchen</p>
|
||||
<p>Jetzt Bessa Einfach! • Knapp-Kantine Wrapper • <span id="current-year">${new Date().getFullYear()}</span> by Kaufi 😃👍 mit Hilfe von KI 🤖</p>
|
||||
</footer>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
25
style.css
25
style.css
@@ -875,42 +875,31 @@ body {
|
||||
filter: grayscale(0.4);
|
||||
}
|
||||
|
||||
/* Enhancements for ordered items */
|
||||
.menu-card.past-day .menu-item.ordered {
|
||||
/* No opacity/filter here - fully visible */
|
||||
background: var(--bg-card);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
border: 1px solid #8b5cf6;
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
margin: 0 -1rem 1.5rem -1rem;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
/* Past ordered items get no special frame or shadow, but remain visually distinct by staying fully opaque (via the :not(.ordered) selector above) */
|
||||
|
||||
.menu-item.today-ordered {
|
||||
border: 2px solid #8b5cf6;
|
||||
box-shadow: 0 0 20px rgba(139, 92, 246, 0.4);
|
||||
box-shadow: 0 0 30px rgba(139, 92, 246, 0.6);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
margin: 0 -1rem 1.5rem -1rem;
|
||||
background: var(--bg-card);
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
animation: pulse-glow 3s infinite;
|
||||
animation: pulse-glow-strong 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-glow {
|
||||
@keyframes pulse-glow-strong {
|
||||
0% {
|
||||
box-shadow: 0 0 15px rgba(139, 92, 246, 0.3);
|
||||
box-shadow: 0 0 20px rgba(139, 92, 246, 0.4);
|
||||
}
|
||||
|
||||
50% {
|
||||
box-shadow: 0 0 25px rgba(139, 92, 246, 0.6);
|
||||
box-shadow: 0 0 40px rgba(139, 92, 246, 0.8);
|
||||
}
|
||||
|
||||
100% {
|
||||
box-shadow: 0 0 15px rgba(139, 92, 246, 0.3);
|
||||
box-shadow: 0 0 20px rgba(139, 92, 246, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,20 +41,32 @@ const sandbox = {
|
||||
fetch: async (url) => {
|
||||
// Mock Version Check
|
||||
if (url.includes('version.txt')) {
|
||||
return { ok: true, text: async () => 'v9.9.9' }; // Simulate new version
|
||||
return { ok: true, text: async () => 'v9.9.9', json: async () => ({}) };
|
||||
}
|
||||
// Mock Changelog
|
||||
if (url.includes('changelog.md')) {
|
||||
return { ok: true, text: async () => '## v9.9.9\n- Feature: Cool Stuff' };
|
||||
return { ok: true, text: async () => '## v9.9.9\n- Feature: Cool Stuff', json: async () => ({}) };
|
||||
}
|
||||
return { ok: false }; // Fail others to prevent huge cascades
|
||||
// Mock GitHub Tags API
|
||||
if (url.includes('api.github.com/') || url.includes('/tags')) {
|
||||
return { ok: true, json: async () => [{ name: 'v9.9.9' }] };
|
||||
}
|
||||
// Mock Menu API
|
||||
if (url.includes('/food-menu/menu/')) {
|
||||
return { ok: true, json: async () => ({ dates: [], menu: {} }) };
|
||||
}
|
||||
// Mock Orders API
|
||||
if (url.includes('/user/orders')) {
|
||||
return { ok: true, json: async () => ({ results: [], count: 0 }) };
|
||||
}
|
||||
return { ok: false, status: 404, text: async () => '', json: async () => ({}) };
|
||||
},
|
||||
document: {
|
||||
body: createMockElement('body'),
|
||||
head: createMockElement('head'),
|
||||
createElement: (tag) => createMockElement(tag),
|
||||
querySelector: (sel) => {
|
||||
if (sel === '.material-icons-round.logo-icon') {
|
||||
if (sel === '.logo-img' || sel === '.material-icons-round.logo-icon') {
|
||||
const el = createMockElement('last-updated-icon-mock');
|
||||
// Mock legacy prop for specific test check if needed,
|
||||
// but our generic mock handles replaceWith hook
|
||||
|
||||
@@ -1 +1 @@
|
||||
v1.6.4
|
||||
v1.6.8
|
||||
|
||||
Reference in New Issue
Block a user