app.html 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8" />
  5. <link rel="icon" type="image/png" href="/static/favicon.png" />
  6. <link rel="icon" type="image/png" href="/static/favicon-96x96.png" sizes="96x96" />
  7. <link rel="icon" type="image/svg+xml" href="/static/favicon.svg" />
  8. <link rel="shortcut icon" href="/static/favicon.ico" />
  9. <link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png" />
  10. <meta name="apple-mobile-web-app-title" content="Open WebUI" />
  11. <link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
  12. <meta
  13. name="viewport"
  14. content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover"
  15. />
  16. <meta name="theme-color" content="#171717" />
  17. <meta name="robots" content="noindex,nofollow" />
  18. <meta name="description" content="Open WebUI" />
  19. <link
  20. rel="search"
  21. type="application/opensearchdescription+xml"
  22. title="Open WebUI"
  23. href="/opensearch.xml"
  24. />
  25. <script src="/static/loader.js" defer></script>
  26. <script>
  27. function resizeIframe(obj) {
  28. obj.style.height = obj.contentWindow.document.documentElement.scrollHeight + 'px';
  29. }
  30. </script>
  31. <script>
  32. // On page load or when changing themes, best to add inline in `head` to avoid FOUC
  33. (() => {
  34. const metaThemeColorTag = document.querySelector('meta[name="theme-color"]');
  35. const prefersDarkTheme = window.matchMedia('(prefers-color-scheme: dark)').matches;
  36. if (!localStorage?.theme) {
  37. localStorage.theme = 'system';
  38. }
  39. if (localStorage.theme === 'system') {
  40. document.documentElement.classList.add(prefersDarkTheme ? 'dark' : 'light');
  41. metaThemeColorTag.setAttribute('content', prefersDarkTheme ? '#171717' : '#ffffff');
  42. } else if (localStorage.theme === 'oled-dark') {
  43. document.documentElement.style.setProperty('--color-gray-800', '#101010');
  44. document.documentElement.style.setProperty('--color-gray-850', '#050505');
  45. document.documentElement.style.setProperty('--color-gray-900', '#000000');
  46. document.documentElement.style.setProperty('--color-gray-950', '#000000');
  47. document.documentElement.classList.add('dark');
  48. metaThemeColorTag.setAttribute('content', '#000000');
  49. } else if (localStorage.theme === 'light') {
  50. document.documentElement.classList.add('light');
  51. metaThemeColorTag.setAttribute('content', '#ffffff');
  52. } else if (localStorage.theme === 'her') {
  53. document.documentElement.classList.add('dark');
  54. document.documentElement.classList.add('her');
  55. metaThemeColorTag.setAttribute('content', '#983724');
  56. } else {
  57. document.documentElement.classList.add('dark');
  58. metaThemeColorTag.setAttribute('content', '#171717');
  59. }
  60. window.matchMedia('(prefers-color-scheme: dark)').addListener((e) => {
  61. if (localStorage.theme === 'system') {
  62. if (e.matches) {
  63. document.documentElement.classList.add('dark');
  64. document.documentElement.classList.remove('light');
  65. metaThemeColorTag.setAttribute('content', '#171717');
  66. } else {
  67. document.documentElement.classList.add('light');
  68. document.documentElement.classList.remove('dark');
  69. metaThemeColorTag.setAttribute('content', '#ffffff');
  70. }
  71. }
  72. });
  73. function setSplashImage() {
  74. const logo = document.getElementById('logo');
  75. const isDarkMode = document.documentElement.classList.contains('dark');
  76. if (isDarkMode) {
  77. const darkImage = new Image();
  78. darkImage.src = '/static/splash-dark.png';
  79. darkImage.onload = () => {
  80. logo.src = '/static/splash-dark.png';
  81. logo.style.filter = ''; // Ensure no inversion is applied if splash-dark.png exists
  82. };
  83. darkImage.onerror = () => {
  84. logo.style.filter = 'invert(1)'; // Invert image if splash-dark.png is missing
  85. };
  86. }
  87. }
  88. // Runs after classes are assigned
  89. window.onload = setSplashImage;
  90. })();
  91. </script>
  92. <title>Open WebUI</title>
  93. %sveltekit.head%
  94. </head>
  95. <body data-sveltekit-preload-data="hover">
  96. <div style="display: contents">%sveltekit.body%</div>
  97. <div
  98. id="splash-screen"
  99. style="position: fixed; z-index: 100; top: 0; left: 0; width: 100%; height: 100%"
  100. >
  101. <style type="text/css" nonce="">
  102. html {
  103. overflow-y: scroll !important;
  104. }
  105. </style>
  106. <img
  107. id="logo"
  108. style="
  109. position: absolute;
  110. width: auto;
  111. height: 6rem;
  112. top: 44%;
  113. left: 50%;
  114. transform: translateX(-50%);
  115. "
  116. src="/static/splash.png"
  117. />
  118. <div
  119. style="
  120. position: absolute;
  121. top: 33%;
  122. left: 50%;
  123. width: 24rem;
  124. transform: translateX(-50%);
  125. display: flex;
  126. flex-direction: column;
  127. align-items: center;
  128. "
  129. >
  130. <img
  131. id="logo-her"
  132. style="width: auto; height: 13rem"
  133. src="/static/splash.png"
  134. class="animate-pulse-fast"
  135. />
  136. <div style="position: relative; width: 24rem; margin-top: 0.5rem">
  137. <div
  138. id="progress-background"
  139. style="
  140. position: absolute;
  141. width: 100%;
  142. height: 0.75rem;
  143. border-radius: 9999px;
  144. background-color: #fafafa9a;
  145. "
  146. ></div>
  147. <div
  148. id="progress-bar"
  149. style="
  150. position: absolute;
  151. width: 0%;
  152. height: 0.75rem;
  153. border-radius: 9999px;
  154. background-color: #fff;
  155. "
  156. class="bg-white"
  157. ></div>
  158. </div>
  159. </div>
  160. <!-- <span style="position: absolute; bottom: 32px; left: 50%; margin: -36px 0 0 -36px">
  161. Footer content
  162. </span> -->
  163. </div>
  164. </body>
  165. </html>
  166. <style type="text/css" nonce="">
  167. html {
  168. overflow-y: hidden !important;
  169. }
  170. #splash-screen {
  171. background: #fff;
  172. }
  173. html.dark #splash-screen {
  174. background: #000;
  175. }
  176. html.her #splash-screen {
  177. background: #983724;
  178. }
  179. #logo-her {
  180. display: none;
  181. }
  182. #progress-background {
  183. display: none;
  184. }
  185. #progress-bar {
  186. display: none;
  187. }
  188. html.her #logo {
  189. display: none;
  190. }
  191. html.her #logo-her {
  192. display: block;
  193. filter: invert(1);
  194. }
  195. html.her #progress-background {
  196. display: block;
  197. }
  198. html.her #progress-bar {
  199. display: block;
  200. }
  201. @media (max-width: 24rem) {
  202. html.her #progress-background {
  203. display: none;
  204. }
  205. html.her #progress-bar {
  206. display: none;
  207. }
  208. }
  209. @keyframes pulse {
  210. 50% {
  211. opacity: 0.65;
  212. }
  213. }
  214. .animate-pulse-fast {
  215. animation: pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite;
  216. }
  217. </style>