diff --git a/skills/datastore/assets/mila.webmanifest b/skills/datastore/assets/mila.webmanifest index 7cd7061..58fe1ae 100644 --- a/skills/datastore/assets/mila.webmanifest +++ b/skills/datastore/assets/mila.webmanifest @@ -1,4 +1,5 @@ { + "id": "/family/mila.html", "name": "Mila — Schlaf & Entwicklung", "short_name": "Mila", "description": "Schlaf-, Trink- und Windeltagebuch für Mila Graf", @@ -13,13 +14,25 @@ "src": "/family/mila-icon-192.png", "sizes": "192x192", "type": "image/png", - "purpose": "any maskable" + "purpose": "any" + }, + { + "src": "/family/mila-icon-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" }, { "src": "/family/mila-icon-512.png", "sizes": "512x512", "type": "image/png", - "purpose": "any maskable" + "purpose": "any" + }, + { + "src": "/family/mila-icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" }, { "src": "/family/mila-apple-touch-icon.png", diff --git a/skills/datastore/assets/moritz.webmanifest b/skills/datastore/assets/moritz.webmanifest new file mode 100644 index 0000000..61b9109 --- /dev/null +++ b/skills/datastore/assets/moritz.webmanifest @@ -0,0 +1,20 @@ +{ + "id": "/family/moritz.html", + "name": "Moritz Health", + "short_name": "Health", + "description": "Persönliches Dashboard für Kalorienbilanz, Ernährung und Garmin-Fitness von Moritz.", + "start_url": "/family/moritz.html", + "scope": "/family/", + "display": "standalone", + "orientation": "portrait-primary", + "background_color": "#f8fafc", + "theme_color": "#ffffff", + "icons": [ + { + "src": "data:image/svg+xml;utf8,", + "sizes": "192x192 512x512", + "type": "image/svg+xml", + "purpose": "any" + } + ] +} diff --git a/skills/datastore/scripts/update_moritz_website.py b/skills/datastore/scripts/update_moritz_website.py index 20ac5bb..3d30cde 100644 --- a/skills/datastore/scripts/update_moritz_website.py +++ b/skills/datastore/scripts/update_moritz_website.py @@ -82,8 +82,8 @@ def get_s3_client(): ) -def publish_to_s3(html_content: str, key: str = "moritz.html") -> str: - """Uploads the rendered HTML to MinIO hosting bucket.""" +def publish_to_s3(html_content: str, key: str = "family/moritz.html", data_dir: Optional[Path] = None) -> str: + """Uploads the rendered HTML and webmanifest to MinIO hosting bucket.""" s3 = get_s3_client() s3.put_object( Bucket=DEFAULT_BUCKET, @@ -92,6 +92,22 @@ def publish_to_s3(html_content: str, key: str = "moritz.html") -> str: ContentType="text/html; charset=utf-8", CacheControl="no-cache, no-store, must-revalidate", ) + # Also upload moritz.webmanifest if present + assets_dir = SCRIPT_DIR.parent / "assets" + manifest_file = assets_dir / "moritz.webmanifest" + if not manifest_file.is_file() and data_dir: + manifest_file = data_dir.parent / "public" / "family" / "moritz.webmanifest" + if manifest_file.is_file(): + try: + s3.put_object( + Bucket=DEFAULT_BUCKET, + Key="family/moritz.webmanifest", + Body=manifest_file.read_bytes(), + ContentType="application/manifest+json; charset=utf-8", + CacheControl="no-cache, no-store, must-revalidate", + ) + except Exception as ex: + print(f"Warning: could not upload family/moritz.webmanifest: {ex}", file=sys.stderr) return f"{DEFAULT_BASE_URL}/{key}" @@ -546,7 +562,7 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str: - + @@ -1231,10 +1247,10 @@ def main(): # 2. Upload strictly to protected S3 hosting under /family/ if not args.skip_upload: try: - url = publish_to_s3(html, key="family/moritz.html") + url = publish_to_s3(html, key="family/moritz.html", data_dir=data_dir) print(f"🚀 Published successfully to: {url}") # Also publish to /family/nutrition.html for backwards compatibility - publish_to_s3(html, key="family/nutrition.html") + publish_to_s3(html, key="family/nutrition.html", data_dir=data_dir) except Exception as e: print(f"⚠️ S3 upload failed (local testing?): {e}", file=sys.stderr) diff --git a/skills/datastore/scripts/update_website.py b/skills/datastore/scripts/update_website.py index d073ebc..66f58ae 100644 --- a/skills/datastore/scripts/update_website.py +++ b/skills/datastore/scripts/update_website.py @@ -464,9 +464,9 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str: """ - # PWA Manifest (RFC-compliant base64 data URI + external webmanifest) - import base64 + # PWA Manifest manifest_dict = { + "id": "/family/mila.html", "name": "Mila — Schlaf & Entwicklung", "short_name": "Mila", "description": "Schlaf-, Trink- und Windeltagebuch für Mila Graf", @@ -481,13 +481,25 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str: "src": "/family/mila-icon-192.png", "sizes": "192x192", "type": "image/png", - "purpose": "any maskable" + "purpose": "any" + }, + { + "src": "/family/mila-icon-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" }, { "src": "/family/mila-icon-512.png", "sizes": "512x512", "type": "image/png", - "purpose": "any maskable" + "purpose": "any" + }, + { + "src": "/family/mila-icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" }, { "src": "/family/mila-apple-touch-icon.png", @@ -501,8 +513,6 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str: } ] } - manifest_json = json.dumps(manifest_dict) - manifest_uri = f"data:application/manifest+json;base64,{base64.b64encode(manifest_json.encode('utf-8')).decode('utf-8')}" # Full HTML Document html = f""" @@ -523,8 +533,7 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str: - - + @@ -615,9 +624,13 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str: - +