Badges ("NEU", "HANDGEMACHT" ...) sitzen direkt auf Produktfotos mit
unterschiedlichsten Hintergründen — die alte, sehr transparente Pille
ging auf manchen Fotos optisch unter. Gleiche Farben/gleicher Stil,
aber kräftigerer (deutlich weniger transparenter) Hintergrund + eigener
Rand + dezenter Schlagschatten hinterm Text für Kontrast auf jedem
Untergrund.
Den eigentlichen Grund für das wacklige Verhalten beim Installieren des
Admin-Bereichs gefunden: Sveltia CMS liest selbst den "logo"-Eintrag in
config.yml (eigentlich nur fürs Branding IN der CMS-Oberfläche gedacht)
und fügt daraus automatisch EIGENE Icon-/Manifest-Verknüpfungen in den
<head> ein — u.a. ein live generiertes, eigenes Manifest als blob:-URL
— NACH unseren eigenen. Zwei "rel=manifest"-Links gleichzeitig sind
technisch erlaubt, aber welcher beim Installieren gewinnt, war nicht
zuverlässig vorhersagbar. Das erklärt, warum es mal geklappt hat und
mal nicht, unabhängig vom Icon-Inhalt selbst.
Fix: ein MutationObserver entfernt Sveltias eigene, automatisch
eingefügte Icon-/Manifest-Verknüpfungen sofort wieder, sobald sie
auftauchen — übrig bleiben ausschließlich unsere eigenen (Favicon =
echtes Logo, Install-Icon = lila V). Verifiziert: nach vollständigem
Laden inkl. Sveltia sind nur noch unsere 5 eigenen Verknüpfungen im
<head> vorhanden, 0 Installability-Errors.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
159 lines
8.1 KiB
HTML
159 lines
8.1 KiB
HTML
<!doctype html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<meta name="robots" content="noindex" />
|
||
<title>Van's DIY & Bastelbedarf – Admin</title>
|
||
<link rel="icon" type="image/x-icon" href="/favicon.ico" sizes="any" />
|
||
<link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32" />
|
||
<link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16" />
|
||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||
<link rel="manifest" href="/admin/manifest.webmanifest" />
|
||
<meta name="theme-color" content="#0a0910" />
|
||
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Fraunces:opsz,[email protected],500;9..144,600;9..144,700&display=swap" rel="stylesheet" />
|
||
<style>
|
||
/* Sveltia CMS optisch an die eigentliche Website angepasst — nutzt Sveltias eigenes
|
||
CSS-Variablen-Theming-System (--sui-*, "Sveltia UI"), keine geratenen internen
|
||
Klassennamen. Das ist zwar nirgends offiziell als öffentliche Theming-API dokumentiert,
|
||
aber es sind echte, durchgängig im ganzen Sveltia-Interface verwendete Design-Tokens —
|
||
deutlich robuster als CSS gegen zufällige Klassennamen zu schreiben. Falls ein
|
||
künftiges Sveltia-Update diese Variablennamen ändert, fällt die Oberfläche einfach
|
||
wieder auf ihr Standard-Blau zurück statt kaputtzugehen.
|
||
*/
|
||
/* !important nötig: Sveltia hängt sein eigenes Stylesheet erst NACH dieser Seite ein,
|
||
gewinnt also bei gleicher Spezifität normalerweise die Kaskade. Mit !important setzt
|
||
sich unsere Optik trotzdem zuverlässig durch, unabhängig von der Ladereihenfolge. */
|
||
:root {
|
||
/* Schiebt alle neutralen Grautöne/Ränder der Oberfläche Richtung Lila — wie der
|
||
Rest der Seite (statt Sveltias Standard-Blaugrau). */
|
||
--sui-base-hue: 248 !important;
|
||
|
||
/* Mischung aus Lila und Babyblau statt einer einzelnen Akzentfarbe: der normale Zustand
|
||
(Buttons, aktive Felder, Links) ist babyblau, Hover-/Fokus-/Auswahl-Zustände (die den
|
||
"-dark"-Ton nutzen) kippen ins Lila (der gleiche Violett-Ton wie die Verlaufsränder auf
|
||
der eigentlichen Website) — dadurch entsteht überall im Interface ein echter Farbmix,
|
||
nicht nur eine Einzelfarbe. */
|
||
--sui-primary-accent-color: #8ec9f0 !important;
|
||
--sui-primary-accent-color-light: #b9e0fa !important;
|
||
--sui-primary-accent-color-dark: #9b7fd6 !important;
|
||
--sui-primary-accent-color-text: #8ec9f0 !important;
|
||
--sui-primary-accent-color-inverted: #0a0910 !important;
|
||
--sui-primary-accent-color-translucent: rgba(155, 127, 214, 0.45) !important;
|
||
--sui-primary-accent-color-translucent-light: rgba(142, 201, 240, 0.3) !important;
|
||
|
||
/* Gleiche Schriftart wie der Rest der Seite statt Sveltias Standardschrift. */
|
||
--sui-font-family-default: "Inter", system-ui, sans-serif !important;
|
||
}
|
||
|
||
/* Zahlenfelder ohne die klobigen Auf/Ab-Pfeile — dezenter, aufgeräumter. */
|
||
input[type="number"]::-webkit-outer-spin-button,
|
||
input[type="number"]::-webkit-inner-spin-button {
|
||
-webkit-appearance: none;
|
||
margin: 0;
|
||
}
|
||
input[type="number"] {
|
||
-moz-appearance: textfield;
|
||
}
|
||
|
||
/* Überschriften mit derselben edlen Serifenschrift wie auf der eigentlichen Website
|
||
(dort --font-head: Fraunces) statt der Standard-Sans-Serif — Sveltia selbst bietet dafür
|
||
kein eigenes CSS-Token, deshalb hier über die stabilen, semantischen HTML-Tags gesetzt
|
||
statt über interne Klassennamen (bleibt robust, auch wenn sich Sveltias Aufbau ändert). */
|
||
h1, h2, h3 {
|
||
font-family: "Fraunces", "Playfair Display", Georgia, serif !important;
|
||
}
|
||
|
||
/* Schwebender "Installieren"-Button — nur sichtbar, wenn der Browser eine Installation
|
||
wirklich anbietet (siehe Script unten). position:fixed statt normaler Dokumentfluss,
|
||
damit er unabhängig davon funktioniert, wie Sveltia sein eigenes UI in <body> aufbaut. */
|
||
#install-btn {
|
||
display: none;
|
||
position: fixed;
|
||
bottom: 1.2rem;
|
||
right: 1.2rem;
|
||
z-index: 9999;
|
||
align-items: center;
|
||
gap: 0.5em;
|
||
padding: 0.7em 1.1em;
|
||
border-radius: 999px;
|
||
background: linear-gradient(135deg, #9b7fd6, #2e1b47);
|
||
border: 1px solid rgba(155, 127, 214, 0.6);
|
||
color: #f4f1f7;
|
||
font-family: "Inter", system-ui, sans-serif;
|
||
font-size: 0.88rem;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
box-shadow: 0 10px 24px -8px rgba(0, 0, 0, 0.55);
|
||
}
|
||
#install-btn:hover { filter: brightness(1.1); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<!-- Sveltia CMS: quelloffen (MIT), läuft komplett im Browser, bearbeitet die Inhalte
|
||
direkt im GitHub-Repo. Kein eigener Server nötig — siehe config.yml für die
|
||
Feld-Definitionen (Produkte, Kategorien). -->
|
||
<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>
|
||
|
||
<button type="button" id="install-btn" title="Admin als App installieren">⬇️ Installieren</button>
|
||
<script>
|
||
// WICHTIG gefundener Grund für das wacklige Installations-Icon bisher: Sveltia CMS liest
|
||
// selbst den "logo"-Eintrag oben in config.yml (der eigentlich nur fürs Branding IN der
|
||
// CMS-Oberfläche gedacht ist) und fügt daraus automatisch EIGENE <link rel="icon">,
|
||
// <link rel="apple-touch-icon"> und sogar ein eigenes, live generiertes
|
||
// <link rel="manifest"> (als blob:-URL) in den <head> ein — NACH unseren eigenen, fest
|
||
// im HTML stehenden Verknüpfungen. Zwei "rel=manifest"-Links gleichzeitig sind erlaubt,
|
||
// aber welcher davon beim Installieren gewinnt, ist nicht zuverlässig vorhersagbar —
|
||
// genau das erklärt, warum es mal geklappt hat und mal nicht. Fix: ein MutationObserver
|
||
// entfernt Sveltias eigene Icon-/Manifest-Verknüpfungen SOFORT wieder, sobald sie
|
||
// auftauchen, damit ausschließlich unsere eigenen (mit dem lila "V") übrig bleiben.
|
||
(function () {
|
||
var eigeneManifestUrl = location.origin + "/admin/manifest.webmanifest";
|
||
var beobachter = new MutationObserver(function (mutationen) {
|
||
mutationen.forEach(function (mutation) {
|
||
mutation.addedNodes.forEach(function (node) {
|
||
if (node.nodeName !== "LINK") return;
|
||
var rel = node.getAttribute("rel");
|
||
if (rel === "manifest" && node.href !== eigeneManifestUrl) node.remove();
|
||
if (rel === "icon" && node.href.indexOf("/logo.png") !== -1) node.remove();
|
||
if (rel === "apple-touch-icon" && node.href.indexOf("data:") === 0) node.remove();
|
||
});
|
||
});
|
||
});
|
||
beobachter.observe(document.head, { childList: true });
|
||
})();
|
||
|
||
// Gleiches Prinzip wie auf der Hauptseite: Button nur zeigen, wenn der Browser die
|
||
// Installation wirklich anbietet, und nicht mehr, sobald bereits als App installiert.
|
||
(function () {
|
||
var btn = document.getElementById("install-btn");
|
||
var laeuftBereitsAlsApp = window.matchMedia("(display-mode: standalone)").matches;
|
||
var promptEvent = null;
|
||
if (!laeuftBereitsAlsApp) {
|
||
window.addEventListener("beforeinstallprompt", function (e) {
|
||
e.preventDefault();
|
||
promptEvent = e;
|
||
btn.style.display = "flex";
|
||
});
|
||
}
|
||
btn.addEventListener("click", function () {
|
||
if (!promptEvent) return;
|
||
btn.style.display = "none";
|
||
promptEvent.prompt();
|
||
promptEvent.userChoice.then(function () { promptEvent = null; });
|
||
});
|
||
window.addEventListener("appinstalled", function () {
|
||
btn.style.display = "none";
|
||
});
|
||
if ("serviceWorker" in navigator) {
|
||
window.addEventListener("load", function () {
|
||
navigator.serviceWorker.register("/sw.js").catch(function () {});
|
||
});
|
||
}
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|