Download ui/index.html from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 19.4 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/ui/index.html
- Command line
-
hf download hf://SaylorTwift/openclaw/ui/index.html
-
curl -L -o index.html https://huggingface.co/SaylorTwift/openclaw/resolve/main/ui/index.html
19.4 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta | |
| name="viewport" | |
| content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content" | |
| /> | |
| <title>OpenClaw Control</title> | |
| <meta name="color-scheme" content="dark light" /> | |
| <!-- These mirror the claw theme's --bg tokens for first paint; runtime theme application keeps them synchronized. --> | |
| <meta name="theme-color" media="(prefers-color-scheme: light)" content="#faf9f7" /> | |
| <meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0e1015" /> | |
| <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> | |
| <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png" /> | |
| <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" /> | |
| <link rel="manifest" href="/manifest.webmanifest" crossorigin="use-credentials" /> | |
| <script data-cfasync="false"> | |
| // Configure Zod before module evaluation so its JIT probe cannot violate strict CSP. | |
| globalThis.__zod_globalConfig ??= {}; | |
| globalThis.__zod_globalConfig.jitless = true; | |
| (function () { | |
| var THEMES = { | |
| claw: 1, | |
| knot: 1, | |
| dash: 1, | |
| absolutely: 1, | |
| tide: 1, | |
| beacon: 1, | |
| phosphor: 1, | |
| crt: 1, | |
| manuscript: 1, | |
| rose: 1, | |
| miami: 1, | |
| }; | |
| var MODES = { system: 1, light: 1, dark: 1 }; | |
| var LEGACY = { | |
| dark: "claw:dark", | |
| light: "claw:light", | |
| openknot: "knot:dark", | |
| fieldmanual: "dash:dark", | |
| clawdash: "dash:light", | |
| system: "claw:system", | |
| }; | |
| try { | |
| var keys = Object.keys(localStorage); | |
| var raw; | |
| for (var i = 0; i < keys.length; i++) { | |
| if (keys[i].indexOf("openclaw.control.settings.v1") === 0) { | |
| raw = localStorage.getItem(keys[i]); | |
| if (raw) break; | |
| } | |
| } | |
| var s = raw ? JSON.parse(raw) : null; | |
| var t = s && s.theme; | |
| var m = s && s.themeMode; | |
| if (typeof t !== "string") t = ""; | |
| if (typeof m !== "string") m = ""; | |
| var legacy = LEGACY[t]; | |
| var theme = THEMES[t] ? t : legacy ? legacy.split(":")[0] : "claw"; | |
| var mode = MODES[m] ? m : legacy ? legacy.split(":")[1] : "system"; | |
| if (mode === "system") { | |
| mode = window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark"; | |
| } | |
| // family -> [dark, light] resolved names. Kept in lockstep with | |
| // resolveTheme() in app/theme.ts and the files in public/themes. | |
| var FAMILIES = { | |
| knot: ["openknot", "openknot-light"], | |
| dash: ["dash", "dash-light"], | |
| absolutely: ["absolutely", "absolutely-light"], | |
| tide: ["tide", "tide-light"], | |
| beacon: ["beacon", "beacon-light"], | |
| phosphor: ["phosphor", "phosphor-light"], | |
| crt: ["crt", "crt-light"], | |
| manuscript: ["manuscript", "manuscript-light"], | |
| rose: ["rose", "rose-light"], | |
| miami: ["miami", "miami-light"], | |
| }; | |
| var pair = FAMILIES[theme]; | |
| var resolved = pair | |
| ? pair[mode === "light" ? 1 : 0] | |
| : mode === "light" | |
| ? "light" | |
| : "dark"; | |
| if (pair) { | |
| // Script-created links need explicit render blocking before first paint. | |
| // The gateway stamps the mount prefix and asset version before this runs. | |
| var base = | |
| document.documentElement.getAttribute("data-openclaw-control-ui-base-path") || ""; | |
| var buildId = document.documentElement.getAttribute( | |
| "data-openclaw-control-ui-build-id", | |
| ); | |
| var version = buildId ? "?v=" + encodeURIComponent(buildId) : ""; | |
| var palette = document.createElement("link"); | |
| palette.rel = "stylesheet"; | |
| palette.setAttribute("blocking", "render"); | |
| palette.id = "openclaw-theme-palette-" + theme; | |
| palette.onerror = function () { | |
| palette.remove(); | |
| }; | |
| palette.href = base + "/themes/" + theme + ".css" + version; | |
| document.head.appendChild(palette); | |
| } | |
| document.documentElement.setAttribute("data-theme", resolved); | |
| var resolvedMode = resolved.includes("light") ? "light" : "dark"; | |
| document.documentElement.setAttribute("data-theme-mode", resolvedMode); | |
| // Plugin semantic styles select on [data-theme-resolved]; keep in lockstep. | |
| document.documentElement.setAttribute("data-theme-resolved", resolvedMode); | |
| } catch (e) {} | |
| })(); | |
| </script> | |
| <style> | |
| /* Paint before the app stylesheet arrives so WebKit never exposes a white | |
| document between its native dark canvas and the persisted UI theme. */ | |
| html, | |
| body { | |
| min-height: 100%; | |
| } | |
| html { | |
| background: #0e1015; | |
| color-scheme: dark; | |
| } | |
| html[data-theme-mode="light"] { | |
| background: #faf9f7; | |
| color-scheme: light; | |
| } | |
| html[data-theme="openknot"] { | |
| background: #080808; | |
| } | |
| html[data-theme="openknot-light"] { | |
| background: #f9f9fb; | |
| } | |
| html[data-theme="dash"] { | |
| background: #1a1210; | |
| } | |
| html[data-theme="dash-light"] { | |
| background: #f7f2ec; | |
| } | |
| html[data-theme="absolutely"] { | |
| background: #1c1c1a; | |
| } | |
| html[data-theme="absolutely-light"] { | |
| background: #faf9f5; | |
| } | |
| html[data-theme="tide"] { | |
| background: #10151b; | |
| } | |
| html[data-theme="tide-light"] { | |
| background: #f7f9fb; | |
| } | |
| html[data-theme="beacon"] { | |
| background: #000000; | |
| } | |
| html[data-theme="beacon-light"] { | |
| background: #ffffff; | |
| } | |
| html[data-theme="phosphor"] { | |
| background: #0a0f0a; | |
| } | |
| html[data-theme="phosphor-light"] { | |
| background: #f4f7f4; | |
| } | |
| html[data-theme="crt"] { | |
| background: #090a09; | |
| } | |
| html[data-theme="crt-light"] { | |
| background: #f5f5f4; | |
| } | |
| html[data-theme="manuscript"] { | |
| background: #211e18; | |
| } | |
| html[data-theme="manuscript-light"] { | |
| background: #f6f1e4; | |
| } | |
| html[data-theme="rose"] { | |
| background: #191724; | |
| } | |
| html[data-theme="rose-light"] { | |
| background: #faf4ed; | |
| } | |
| html[data-theme="miami"] { | |
| background: #140f1e; | |
| } | |
| html[data-theme="miami-light"] { | |
| background: #f7f3f6; | |
| } | |
| body { | |
| margin: 0; | |
| min-height: 100%; | |
| background: inherit; | |
| color-scheme: inherit; | |
| } | |
| body.openclaw-mount-fallback-active { | |
| margin: 0; | |
| min-width: 320px; | |
| color: #eef4f8; | |
| background: #101418; | |
| font-family: | |
| Inter, | |
| ui-sans-serif, | |
| system-ui, | |
| -apple-system, | |
| BlinkMacSystemFont, | |
| "Segoe UI", | |
| sans-serif; | |
| } | |
| body.openclaw-mount-fallback-active openclaw-app { | |
| display: none; | |
| } | |
| .mount-fallback { | |
| box-sizing: border-box; | |
| /* The app stylesheet clips the root scrollers, so this pre-app error | |
| surface must own its scrolling on short windows. dvh keeps the | |
| scroll range inside the visible mobile viewport; vh is the fallback. */ | |
| height: 100vh; | |
| height: 100dvh; | |
| overflow-y: auto; | |
| padding: 24px; | |
| place-items: center; | |
| place-items: safe center; | |
| } | |
| .mount-fallback:not([hidden]) { | |
| display: grid; | |
| } | |
| .mount-fallback__panel { | |
| box-sizing: border-box; | |
| width: min(100%, 640px); | |
| border: 1px solid rgba(148, 163, 184, 0.28); | |
| border-radius: 8px; | |
| background: #151b21; | |
| box-shadow: 0 24px 80px rgba(0, 0, 0, 0.36); | |
| padding: 28px; | |
| } | |
| .mount-fallback__eyebrow { | |
| margin: 0 0 10px; | |
| color: #9fb0bd; | |
| font-size: 0.78rem; | |
| font-weight: 700; | |
| letter-spacing: 0.08em; | |
| text-transform: uppercase; | |
| } | |
| .mount-fallback__panel h1 { | |
| margin: 0; | |
| color: inherit; | |
| font-size: clamp(1.5rem, 3vw, 2rem); | |
| line-height: 1.15; | |
| } | |
| .mount-fallback__panel p { | |
| margin: 16px 0 0; | |
| color: #c8d3da; | |
| font-size: 1rem; | |
| line-height: 1.6; | |
| } | |
| .mount-fallback__panel ul { | |
| margin: 18px 0 0; | |
| padding-left: 1.2rem; | |
| color: #c8d3da; | |
| line-height: 1.6; | |
| } | |
| .mount-fallback__panel a { | |
| color: #8bd3ff; | |
| text-decoration-thickness: 0.08em; | |
| text-underline-offset: 0.18em; | |
| } | |
| .mount-fallback__actions { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 10px; | |
| margin-top: 24px; | |
| } | |
| .mount-fallback__button { | |
| min-height: 42px; | |
| border: 1px solid rgba(148, 163, 184, 0.36); | |
| border-radius: 6px; | |
| padding: 0 16px; | |
| color: inherit; | |
| background: transparent; | |
| font: inherit; | |
| font-weight: 700; | |
| } | |
| .mount-fallback__button--primary { | |
| border-color: #66c2ff; | |
| color: #061019; | |
| background: #8bd3ff; | |
| } | |
| .mount-fallback__panel:focus { | |
| outline: none; | |
| } | |
| .mount-fallback__button:focus-visible, | |
| .mount-fallback__panel a:focus-visible { | |
| outline: 3px solid #f9c74f; | |
| outline-offset: 3px; | |
| } | |
| html[data-theme-mode="light"] body.openclaw-mount-fallback-active { | |
| color: #151b21; | |
| background: #f5f7fa; | |
| } | |
| html[data-theme-mode="light"] .mount-fallback__panel { | |
| border-color: rgba(71, 85, 105, 0.22); | |
| background: #ffffff; | |
| box-shadow: 0 24px 80px rgba(15, 23, 42, 0.14); | |
| } | |
| html[data-theme-mode="light"] .mount-fallback__eyebrow, | |
| html[data-theme-mode="light"] .mount-fallback__panel p, | |
| html[data-theme-mode="light"] .mount-fallback__panel ul { | |
| color: #4b5963; | |
| } | |
| html[data-theme-mode="light"] .mount-fallback__panel a { | |
| color: #0369a1; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <openclaw-app></openclaw-app> | |
| <section | |
| id="openclaw-mount-fallback" | |
| class="mount-fallback" | |
| data-openclaw-mount-timeout-ms="12000" | |
| role="alert" | |
| aria-labelledby="openclaw-mount-fallback-title" | |
| hidden | |
| > | |
| <div class="mount-fallback__panel" tabindex="-1"> | |
| <p class="mount-fallback__eyebrow">OpenClaw Control UI</p> | |
| <h1 id="openclaw-mount-fallback-title">Control UI did not start</h1> | |
| <p id="openclaw-mount-fallback-summary"> | |
| The browser loaded the static page, but the app bundle did not start. The gateway may be | |
| restarting, or this page may reference assets from a different OpenClaw version. | |
| </p> | |
| <ul> | |
| <li>If startup fails, OpenClaw will retry the current app bundle automatically.</li> | |
| <li>If this persists, reload or try a clean browser profile.</li> | |
| <li> | |
| See | |
| <a | |
| href="https://docs.openclaw.ai/web/control-ui#blank-control-ui-page" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| >Control UI troubleshooting</a | |
| >. | |
| </li> | |
| </ul> | |
| <div class="mount-fallback__actions"> | |
| <button | |
| type="button" | |
| id="openclaw-mount-retry" | |
| class="mount-fallback__button mount-fallback__button--primary" | |
| > | |
| Try again | |
| </button> | |
| <button type="button" id="openclaw-mount-wait" class="mount-fallback__button"> | |
| Keep waiting | |
| </button> | |
| </div> | |
| </div> | |
| </section> | |
| <script data-cfasync="false"> | |
| (function () { | |
| var app = document.querySelector("openclaw-app"); | |
| var fallback = document.getElementById("openclaw-mount-fallback"); | |
| if (!app || !fallback) return; | |
| var panel = fallback.querySelector(".mount-fallback__panel"); | |
| var title = document.getElementById("openclaw-mount-fallback-title"); | |
| var summary = document.getElementById("openclaw-mount-fallback-summary"); | |
| var failureSummary = summary.textContent; | |
| var retry = document.getElementById("openclaw-mount-retry"); | |
| var wait = document.getElementById("openclaw-mount-wait"); | |
| var rawDelay = Number(fallback.getAttribute("data-openclaw-mount-timeout-ms")); | |
| var delay = Number.isFinite(rawDelay) && rawDelay > 0 ? rawDelay : 12000; | |
| var maxRecoveryAttempts = 6; | |
| var timer; | |
| var recoveryTimer; | |
| var recoveryAttempt = 0; | |
| var recoveryNavigation = false; | |
| var appStarted = false; | |
| var documentLoaded = document.readyState === "complete"; | |
| var recoveryController; | |
| try { | |
| var initialUrl = new URL(window.location.href); | |
| recoveryNavigation = initialUrl.searchParams.has("openclaw_mount_recovery"); | |
| if (recoveryNavigation) { | |
| initialUrl.searchParams.delete("openclaw_mount_recovery"); | |
| window.history.replaceState(null, "", initialUrl.href); | |
| } | |
| } catch (e) {} | |
| function hideFallback() { | |
| fallback.hidden = true; | |
| document.body.classList.remove("openclaw-mount-fallback-active"); | |
| } | |
| function setSummary(text) { | |
| if (summary) summary.textContent = text; | |
| } | |
| function cancelRecovery() { | |
| window.clearTimeout(recoveryTimer); | |
| if (recoveryController) recoveryController.abort(); | |
| recoveryController = undefined; | |
| } | |
| function scheduleRecovery() { | |
| window.clearTimeout(recoveryTimer); | |
| if (appStarted || recoveryAttempt >= maxRecoveryAttempts) return; | |
| var retryDelay = Math.min(delay, 1000 * Math.pow(2, recoveryAttempt)); | |
| recoveryTimer = window.setTimeout(retryCurrentDocument, retryDelay); | |
| } | |
| function finishRecoveryAttempt() { | |
| recoveryController = undefined; | |
| if (appStarted) return; | |
| if (recoveryAttempt >= maxRecoveryAttempts) { | |
| setSummary( | |
| "The gateway is still unavailable. Try again, then check the troubleshooting guide if the problem persists.", | |
| ); | |
| return; | |
| } | |
| setSummary( | |
| "The gateway is not reachable yet. OpenClaw will keep retrying while it restarts.", | |
| ); | |
| scheduleRecovery(); | |
| } | |
| function unregisterServiceWorkers() { | |
| if (!navigator.serviceWorker?.getRegistrations) return; | |
| // Recovery must not depend on a possibly broken worker. Navigations bypass it, | |
| // so a reload can self-heal after the registrations are removed. | |
| void navigator.serviceWorker | |
| .getRegistrations() | |
| .then(function (registrations) { | |
| return Promise.all( | |
| registrations.map(function (registration) { | |
| return registration.unregister(); | |
| }), | |
| ); | |
| }) | |
| .catch(function () {}); | |
| } | |
| function retryCurrentDocument() { | |
| if ( | |
| appStarted || | |
| recoveryController || | |
| recoveryAttempt >= maxRecoveryAttempts || | |
| typeof window.fetch !== "function" | |
| ) | |
| return; | |
| var documentUrl = new URL(window.location.href); | |
| if (recoveryNavigation) { | |
| setSummary( | |
| "A fresh page still could not start the Control UI. Try again, then check the troubleshooting guide if the problem persists.", | |
| ); | |
| return; | |
| } | |
| recoveryAttempt += 1; | |
| documentUrl.searchParams.set("openclaw_mount_recovery", String(Date.now())); | |
| var controller = new AbortController(); | |
| recoveryController = controller; | |
| var requestTimer = window.setTimeout(function () { | |
| controller.abort(); | |
| }, delay); | |
| window | |
| .fetch(documentUrl.href, { | |
| cache: "no-store", | |
| credentials: "same-origin", | |
| signal: controller.signal, | |
| }) | |
| .then(function (response) { | |
| if (!response.ok) throw new Error("gateway unavailable"); | |
| if (!appStarted && recoveryController === controller) | |
| window.location.replace(documentUrl.href); | |
| }) | |
| .catch(function () { | |
| if (recoveryController !== controller) return; | |
| unregisterServiceWorkers(); | |
| finishRecoveryAttempt(); | |
| }) | |
| .finally(function () { | |
| window.clearTimeout(requestTimer); | |
| }); | |
| } | |
| function showFallback() { | |
| if (appStarted) return; | |
| title.textContent = documentLoaded | |
| ? "Control UI did not start" | |
| : "Control UI is still loading"; | |
| fallback.setAttribute("role", documentLoaded ? "alert" : "status"); | |
| setSummary( | |
| documentLoaded | |
| ? failureSummary | |
| : "The browser is still loading the app. OpenClaw will keep waiting without interrupting the download.", | |
| ); | |
| if (documentLoaded) retryCurrentDocument(); | |
| fallback.hidden = false; | |
| document.body.classList.add("openclaw-mount-fallback-active"); | |
| if (documentLoaded && panel && typeof panel.focus === "function") { | |
| try { | |
| panel.focus({ preventScroll: true }); | |
| } catch (e) { | |
| panel.focus(); | |
| } | |
| } | |
| } | |
| function armFallbackTimer() { | |
| window.clearTimeout(timer); | |
| timer = window.setTimeout(showFallback, delay); | |
| } | |
| armFallbackTimer(); | |
| // Deferred module graphs settle before DOMContentLoaded. A slow download | |
| // is not a failed bootstrap: replacing the document would cancel it. | |
| document.addEventListener( | |
| "DOMContentLoaded", | |
| function () { | |
| documentLoaded = true; | |
| if (!fallback.hidden) showFallback(); | |
| }, | |
| { once: true }, | |
| ); | |
| window.addEventListener( | |
| "openclaw-control-ui-rendered", | |
| function () { | |
| appStarted = true; | |
| window.clearTimeout(timer); | |
| cancelRecovery(); | |
| hideFallback(); | |
| }, | |
| { once: true }, | |
| ); | |
| if (retry) { | |
| retry.addEventListener("click", function () { | |
| cancelRecovery(); | |
| unregisterServiceWorkers(); | |
| window.location.reload(); | |
| }); | |
| } | |
| if (wait) { | |
| wait.addEventListener("click", function () { | |
| hideFallback(); | |
| cancelRecovery(); | |
| recoveryAttempt = 0; | |
| armFallbackTimer(); | |
| }); | |
| } | |
| })(); | |
| </script> | |
| <script data-cfasync="false" type="module" src="/src/main.ts"></script> | |
| </body> | |
| </html> | |