1
<!DOCTYPE html>
2
-<html lang="en" data-splash-theme="dark">
2
+<html lang="en">
3
4
<head>
5
<meta charset="UTF-8">
6
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
7
<title>Agent Zero</title>
8
9
- <script>
10
- try {
11
- if (localStorage.getItem("darkMode") === "false") document.documentElement.dataset.splashTheme = "light"
12
- } catch (_) {}
13
- Promise.all([
14
- new Promise((resolve) => addEventListener("load", resolve, { once: true })),
15
- new Promise((resolve) => document.addEventListener("webui-bundle-loaded", resolve, { once: true })),
16
- new Promise((resolve) => document.addEventListener("webui-extensions-loaded", resolve, { once: true })),
17
- ]).then(() => {
18
- const splash = document.getElementById("startup-splash")
19
- if (!splash) return
20
- splash.addEventListener("transitionend", () => splash.remove(), { once: true })
21
- splash.classList.add("startup-splash-loaded")
22
- document.documentElement.removeAttribute("data-splash-theme")
23
- })
24
- </script>
25
- <style>
26
- html { background: #131313; }
27
- html[data-splash-theme="light"] { background: #fafafa; }
28
- #startup-splash {
29
- position: fixed; inset: 0; z-index: 2147483647;
30
- display: grid; place-items: center;
9
+ <style id="startup-transition-critical">
10
+ #startup-transition {
11
+ position: fixed;
12
+ inset: 0;
13
+ z-index: 2147483647;
14
+ display: grid;
15
+ place-items: center;
16
+ margin: 0;
17
background: #131313;
32
- transition: opacity .32s ease, visibility 0s linear .32s;
18
+ color: #fff;
19
+ opacity: 1;
20
+ transition: opacity 240ms ease;
21
+ }
22
+ #startup-transition[data-theme="light"],
23
+ body.light-mode #startup-transition { background: #fafafa; color: #000; }
24
+ #startup-transition > svg {
25
+ width: clamp(12rem, 34vw, 23rem);
26
+ max-width: 72vw;
27
+ height: auto;
28
+ opacity: 1;
29
+ animation: none;
30
+ }
31
+ #startup-transition > p {
32
+ position: absolute;
33
+ width: 1px;
34
+ height: 1px;
35
+ overflow: hidden;
36
+ clip-path: inset(50%);
37
}
34
- html[data-splash-theme="light"] #startup-splash { background: #fafafa; }
35
- #startup-splash img {
36
- width: clamp(12rem, 34vw, 23rem); max-width: 72vw; height: auto;
37
- opacity: 0; filter: brightness(0) invert(1);
38
- animation: startup-logo-in .55s ease-out .05s forwards;
38
+ #startup-transition.startup-transition-leaving {
39
+ opacity: 0;
40
+ pointer-events: none;
41
}
40
- html[data-splash-theme="light"] #startup-splash img { filter: brightness(0); }
41
- #startup-splash.startup-splash-loaded {
42
- opacity: 0; visibility: hidden; pointer-events: none;
42
+ @media (prefers-reduced-motion: reduce) {
43
+ #startup-transition { transition: none; }
44
}
44
- @keyframes startup-logo-in { to { opacity: 1; } }
45
</style>
46
- <link rel="preload" href="/public/a0-fullDark.svg" as="image" type="image/svg+xml">
46
47
<script>
49
- (async () => {
50
- let bundle
51
- try {
52
- const response = await fetch("/ui/asset-bundle", { credentials: "same-origin" })
53
- if (!response.ok) throw new Error(`Bundle request failed: ${response.status}`)
54
- bundle = await response.json()
55
- } catch (error) {
56
- console.warn("WebUI asset bundle unavailable.", error)
57
- return
58
- } finally {
59
- document.dispatchEvent(new Event("webui-bundle-loaded"))
48
+ if (location.pathname === "/safe") {
49
+ const safeUrl = new URL(location.href)
50
+ safeUrl.searchParams.delete("__direct")
51
+ history.replaceState(null, "", `${safeUrl.pathname}${safeUrl.search}${safeUrl.hash}`)
52
+ if ("serviceWorker" in navigator) {
53
+ navigator.serviceWorker.getRegistrations()
54
+ .then((registrations) => Promise.allSettled(
55
+ registrations.map((registration) => registration.unregister()),
56
+ ))
57
+ .catch((error) => console.warn("Unable to disable service workers.", error))
58
}
59
+ }
60
+ </script>
61
+
62
+ <link rel="icon" type="image/svg+xml" href="public/favicon.svg">
63
+ <link rel="preload" href="/vendor/google/google-icons.woff2" as="font" type="font/woff2" crossorigin>
64
+ <link rel="stylesheet" href="vendor/google/google-icons.css">
65
+ <script>
66
+ (() => {
67
+ const root = document.documentElement
68
+ let applicationReady = false
69
+ let revealStarted = false
70
62
- if (!("serviceWorker" in navigator) || !bundle?.version || !bundle.files) return
63
- try {
64
- const sentWorkers = new WeakSet()
65
- const sendBundle = (worker) => {
66
- if (!worker || sentWorkers.has(worker)) return
67
- sentWorkers.add(worker)
68
- worker.postMessage({ type: "preload-ui-bundle", bundle })
69
- }
70
-
71
- sendBundle(navigator.serviceWorker.controller)
72
- const onControllerChange = () => {
73
- sendBundle(navigator.serviceWorker.controller)
74
- navigator.serviceWorker.removeEventListener("controllerchange", onControllerChange)
75
- }
76
- navigator.serviceWorker.addEventListener("controllerchange", onControllerChange)
77
-
78
- const registrations = await navigator.serviceWorker.getRegistrations()
79
- await Promise.all(
80
- registrations
81
- .filter((registration) => new URL(registration.scope).pathname === "/js/")
82
- .map((registration) => registration.unregister()),
83
- )
84
- const registration = await navigator.serviceWorker.register(
85
- `/sw.js?version=${encodeURIComponent(bundle.version)}`,
86
- { scope: "/", updateViaCache: "none" },
87
- )
88
- sendBundle(registration.installing)
89
- sendBundle(registration.waiting)
90
- sendBundle(registration.active)
91
- sendBundle((await navigator.serviceWorker.ready).active)
92
- } catch (error) {
93
- console.warn("WebUI asset cache unavailable.", error)
71
+ const revealApplication = (force = false) => {
72
+ if (revealStarted || (!force && !applicationReady)) return
73
+ const overlay = document.getElementById("startup-transition")
74
+ if (!overlay) return
75
+ revealStarted = true
76
+ requestAnimationFrame(() => requestAnimationFrame(() => {
77
+ const removeOverlay = () => overlay.remove()
78
+ overlay.classList.add("startup-transition-leaving")
79
+ overlay.addEventListener("transitionend", removeOverlay, { once: true })
80
+ setTimeout(removeOverlay, 600)
81
+ }))
82
}
83
+
84
+ document.addEventListener("webui-extensions-loaded", () => {
85
+ applicationReady = true
86
+ revealApplication()
87
+ }, { once: true })
88
+
89
+ const fontLoad = document.fonts?.load
90
+ ? document.fonts.load('24px "Material Symbols Outlined"')
91
+ : Promise.resolve([])
92
+ fontLoad.then((faces) => {
93
+ if (faces.length > 0) root.classList.add("material-icons-ready")
94
+ }).catch((error) => {
95
+ console.warn("Material Symbols font unavailable.", error)
96
+ })
97
+
98
+ setTimeout(() => revealApplication(true), 8000)
99
})()
100
</script>
97
-
98
- <link rel="icon" type="image/svg+xml" href="public/favicon.svg">
101
+ <link rel="preload" as="style" href="/vendor/fonts/fonts.css" onload="this.onload=null;this.rel='stylesheet'">
102
<link rel="preload" as="style" href="index.css" onload="this.onload=null;this.rel='stylesheet'">
103
+ <link rel="preload" as="style" href="css/loading-indicators.css" onload="this.onload=null;this.rel='stylesheet'">
104
<link rel="preload" as="style" href="css/messages.css" onload="this.onload=null;this.rel='stylesheet'">
105
<link rel="preload" as="style" href="components/messages/action-buttons/simple-action-buttons.css" onload="this.onload=null;this.rel='stylesheet'">
106
<link rel="preload" as="style" href="components/messages/process-group/process-group.css" onload="this.onload=null;this.rel='stylesheet'">
131
<script defer src="vendor/bootstrap/bootstrap.bundle.min.js"></script>
132
133
<!-- Then load Alpine.js -->
130
- <!-- <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js"></script> -->
134
<script defer src="vendor/ace-min/ace.js"></script>
135
<script defer src="vendor/qrcode.min.js"></script>
136
<script type="module" src="js/initFw.js"></script>
143
<script defer src="vendor/katex/katex.min.js" crossorigin="anonymous"></script>
144
<script defer src="vendor/katex/katex.auto-render.min.js" crossorigin="anonymous"></script>
145
143
- <!-- Google Icons -->
144
- <link rel="preload" as="style" href="vendor/google/google-icons.css" onload="this.onload=null;this.rel='stylesheet'">
145
-
146
<!-- Link the PWA manifest file -->
147
<link rel="manifest" href="js/manifest.json">
148
159
timezone: "{{user_timezone_setting}}",
160
timeFormat: "{{user_time_format_setting}}",
161
uiControlVisibility: {{user_ui_control_visibility}},
162
+ webuiExtensions: {{webui_extension_manifest}},
163
};
164
</script>
165
<!-- Plugin head injections (scripts, stylesheets) -->
168
169
<body class="dark-mode device-pointer" x-data>
170
<script>
170
- if (document.documentElement.dataset.splashTheme === "light") document.body.classList.replace("dark-mode", "light-mode")
171
+ try {
172
+ if (localStorage.getItem("darkMode") === "false") document.body.classList.replace("dark-mode", "light-mode")
173
+ } catch (_) {}
174
</script>
172
- <div id="startup-splash" aria-hidden="true">
173
- <img src="/public/a0-fullDark.svg" alt="">
174
- </div>
175
<div class="container">
176
<!-- Sidebar Overlay -->
177
<div id="sidebar-overlay" x-data>
183
<x-component path="sidebar/left-sidebar.html"></x-component>
184
185
<!-- Right Panel (Message History and Input Section) -->
186
- <div id="right-panel" class="panel" >
186
+ <div id="right-panel" class="panel"
187
+ :class="{ 'chat-active': $store.welcomeStore && !$store.welcomeStore.isVisible }">
188
189
<!-- top section with time, status etc. -->
190
<x-component path="chat/top-section/chat-top.html"></x-component>
201
<div id="chat-area-wrapper" x-data x-show="!$store.welcomeStore || !$store.welcomeStore.isVisible">
202
<div id="chat-history"></div>
203
204
+ <div id="chat-loading-splash"
205
+ class="message-window-loader is-loading chat-loading-splash"
206
+ role="status"
207
+ aria-live="polite"
208
+ hidden>
209
+ <span class="loading-indicator-label">Loading chat</span>
210
+ </div>
211
+
212
<!-- Chat Navigation Buttons (floating over chat area) -->
213
<div id="chat-nav-buttons" aria-label="Chat navigation" x-cloak>
214
<button class="btn-icon-action" title="Scroll to top" @click="$store.chatNavigation.scrollToTop()">