overview.html 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <style>
  2. #ov-root {
  3. --ov-bg: #ffffff;
  4. --ov-border: #e5e5e5;
  5. --ov-text: #1f1f1f;
  6. --ov-dim: #676767;
  7. --ov-soft: #f5f5f5;
  8. --ov-shadow: 0 4px 20px rgba(0,0,0,0.08);
  9. background: var(--ov-bg);
  10. border: 1px solid var(--ov-border);
  11. border-radius: 12px;
  12. box-shadow: var(--ov-shadow);
  13. color: var(--ov-text);
  14. padding: 14px;
  15. margin-bottom: 4px;
  16. font-family: 'Segoe UI', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  17. }
  18. body.dark #ov-root {
  19. --ov-bg: #2b2b2b;
  20. --ov-border: #3b3b3b;
  21. --ov-text: #ececec;
  22. --ov-dim: #aaaaaa;
  23. --ov-soft: #343434;
  24. --ov-shadow: 0 8px 22px rgba(0,0,0,0.3);
  25. }
  26. #ov-top {
  27. display: flex;
  28. align-items: center;
  29. justify-content: space-between;
  30. gap: 12px;
  31. margin-bottom: 12px;
  32. }
  33. #ov-user {
  34. display: flex;
  35. align-items: center;
  36. gap: 10px;
  37. min-width: 0;
  38. }
  39. #ov-avatar {
  40. width: 46px;
  41. height: 46px;
  42. border-radius: 50%;
  43. object-fit: cover;
  44. flex-shrink: 0;
  45. border: 1px solid var(--ov-border);
  46. background: var(--ov-soft);
  47. }
  48. #ov-user-meta { min-width: 0; }
  49. #ov-username {
  50. font-size: 15px;
  51. font-weight: 600;
  52. white-space: nowrap;
  53. overflow: hidden;
  54. text-overflow: ellipsis;
  55. }
  56. #ov-usergroup {
  57. margin-top: 1px;
  58. font-size: 12px;
  59. color: var(--ov-dim);
  60. white-space: nowrap;
  61. overflow: hidden;
  62. text-overflow: ellipsis;
  63. }
  64. #ov-actions { display: flex; align-items: center; gap: 8px; }
  65. #ov-logout {
  66. border: 1px solid var(--ov-border);
  67. background: var(--ov-soft);
  68. color: var(--ov-text);
  69. border-radius: 8px;
  70. font-size: 12px;
  71. font-weight: 600;
  72. padding: 6px 10px;
  73. cursor: pointer;
  74. }
  75. #ov-host {
  76. display: flex;
  77. align-items: center;
  78. gap: 8px;
  79. margin-bottom: 10px;
  80. padding: 8px 10px;
  81. border-radius: 9px;
  82. background: var(--ov-soft);
  83. border: 1px solid var(--ov-border);
  84. }
  85. #ov-host-icon-wrapper{
  86. width: 100%;
  87. display: flex;
  88. justify-content: end;
  89. }
  90. #ov-host-icon {
  91. width: 100px;
  92. height: auto;
  93. border-radius: 5px;
  94. object-fit: cover;
  95. background: var(--ov-bg);
  96. margin-top: 1em;
  97. }
  98. #ov-host-text {
  99. min-width: 0;
  100. font-size: 12px;
  101. color: var(--ov-dim);
  102. white-space: nowrap;
  103. overflow: hidden;
  104. text-overflow: ellipsis;
  105. }
  106. #ov-grid {
  107. display: grid;
  108. grid-template-columns: repeat(4, minmax(140px, 1fr));
  109. gap: 8px;
  110. }
  111. .ov-card {
  112. border: 1px solid var(--ov-border);
  113. border-radius: 10px;
  114. background: var(--ov-soft);
  115. padding: 10px;
  116. }
  117. .ov-label {
  118. font-size: 11px;
  119. color: var(--ov-dim);
  120. margin-bottom: 4px;
  121. }
  122. .ov-value {
  123. font-size: 12.5px;
  124. font-weight: 600;
  125. line-height: 1.35;
  126. word-break: break-word;
  127. }
  128. #ov-home-status { display: inline-flex; align-items: center; gap: 6px; }
  129. #ov-home-dot {
  130. width: 8px;
  131. height: 8px;
  132. border-radius: 50%;
  133. background: #c42b1c;
  134. }
  135. #ov-home-dot.online { background: #107c10; }
  136. @media (max-width: 920px) {
  137. #ov-grid { grid-template-columns: repeat(2, minmax(120px, 1fr)); }
  138. }
  139. @media (max-width: 620px) {
  140. #ov-root { padding: 10px; }
  141. #ov-grid { grid-template-columns: 1fr; }
  142. #ov-top { flex-wrap: wrap; }
  143. }
  144. </style>
  145. <div id="ov-root">
  146. <div id="ov-top">
  147. <div id="ov-user">
  148. <img id="ov-avatar" src="../../SystemAO/users/img/user.svg" alt="">
  149. <div id="ov-user-meta">
  150. <div id="ov-username">USER</div>
  151. <div id="ov-usergroup">@usergroup</div>
  152. </div>
  153. </div>
  154. <div id="ov-actions">
  155. <button id="ov-logout" onclick="ovLogout()" locale="overview/logout">Logout</button>
  156. </div>
  157. </div>
  158. <div id="ov-host">
  159. <div id="ov-host-text"><span id="ov-hostname">-</span> · <span id="ov-version">-</span></div>
  160. </div>
  161. <div id="ov-grid">
  162. <div class="ov-card">
  163. <div class="ov-label" locale="overview/used_space">Used Space</div>
  164. <div class="ov-value" id="ov-used">-</div>
  165. </div>
  166. <div class="ov-card">
  167. <div class="ov-label" locale="overview/total_space">Total Space</div>
  168. <div class="ov-value" id="ov-total">-</div>
  169. </div>
  170. <div class="ov-card">
  171. <div class="ov-label" locale="overview/personal_homepage">Homepage</div>
  172. <div class="ov-value" id="ov-home-status"><span id="ov-home-dot"></span><span id="ov-home-text">-</span></div>
  173. </div>
  174. <div class="ov-card">
  175. <div class="ov-label" locale="overview/up_time">Up Time</div>
  176. <div class="ov-value" id="ov-operation" startunix="0">-</div>
  177. </div>
  178. </div>
  179. <div id="ov-host-icon-wrapper">
  180. <img id="ov-host-icon" alt="" src="../../SystemAO/img/failed.png">
  181. </div>
  182. </div>
  183. <script>
  184. (function () {
  185. var overviewLocale = NewAppLocale();
  186. function applyTheme() {
  187. // Theme is driven by body.dark (set by system_setting/main.js and desktopThemeChanged).
  188. // Sync body.dark here for the initial load in case it isn't set yet.
  189. var isDark = false;
  190. try {
  191. if (typeof preferredTheme !== 'undefined') {
  192. isDark = (preferredTheme === 'dark' || preferredTheme === 'darkTheme');
  193. } else {
  194. ao_module_getSystemThemeColor(function (c) {
  195. document.body.classList.toggle('dark', c !== 'whiteTheme');
  196. });
  197. return;
  198. }
  199. } catch (e) {}
  200. document.body.classList.toggle('dark', isDark);
  201. }
  202. function ovS(key, fallback) {
  203. return overviewLocale ? overviewLocale.getString(key, fallback) : fallback;
  204. }
  205. function initHostInfo() {
  206. $.get('../../system/info/getArOZInfo?icon=true', function (data) {
  207. if (data && data.VendorIcon) {
  208. $('#ov-host-icon').attr('src', 'data:image/png;base64,' + data.VendorIcon);
  209. }
  210. $('#ov-hostname').text((data && data.HostName) ? data.HostName : '-');
  211. $('#ov-version').text((data && data.BuildVersion) ? data.BuildVersion : '-');
  212. });
  213. }
  214. function initUserInfo() {
  215. $.get('../../system/users/userinfo', function (data) {
  216. if (!data || data.error !== undefined) return;
  217. $('#ov-username').text(data.Username || 'USER');
  218. if (data.Usergroup && data.Usergroup.length) {
  219. $('#ov-usergroup').text('@' + data.Usergroup.join(','));
  220. }
  221. if (data.Icondata) {
  222. $('#ov-avatar').attr('src', data.Icondata);
  223. }
  224. });
  225. }
  226. function initStorageInfo() {
  227. $.get('../../system/disk/quota/quotaInfo', function (data) {
  228. if (!data || data.error !== undefined) return;
  229. var percentageText = '0%';
  230. if (data.Total === -1) {
  231. $('#ov-total').text(ovS('overview/info/unlimited', 'Unlimited'));
  232. } else if (data.Total === 0) {
  233. $('#ov-total').text(ovS('overview/info/readonly', 'Read Only'));
  234. percentageText = '100%';
  235. } else {
  236. $('#ov-total').text(ao_module_utils.formatBytes(data.Total, 2));
  237. percentageText = parseFloat((data.Used / data.Total) * 100).toFixed(2) + '%';
  238. }
  239. $('#ov-used').text(ao_module_utils.formatBytes(data.Used, 2) + ' (' + percentageText + ')');
  240. });
  241. }
  242. function initHomepageState() {
  243. $.get('../../system/network/www/toggle', function (data) {
  244. var online = (data === true);
  245. $('#ov-home-dot').toggleClass('online', online);
  246. $('#ov-home-text').text(
  247. online
  248. ? ovS('overview/status/online', 'Online')
  249. : ovS('overview/status/offline', 'Offline')
  250. );
  251. });
  252. }
  253. function initRuntimeInfo() {
  254. $.getJSON('../../system/info/getRuntimeInfo', function (data) {
  255. if (!data || data.error !== undefined) return;
  256. $('#ov-operation').text(ao_module_utils.durationConverter(data.ContinuesRuntime));
  257. $('#ov-operation').attr('startunix', data.StartupTime);
  258. accumulateOperationTime();
  259. });
  260. }
  261. function accumulateOperationTime() {
  262. setTimeout(function () {
  263. if ($('#ov-operation').length === 0) return;
  264. var startUnix = parseInt($('#ov-operation').attr('startunix'), 10);
  265. if (isNaN(startUnix) || startUnix <= 0) {
  266. accumulateOperationTime();
  267. return;
  268. }
  269. var newOprTime = parseInt(Date.now() / 1000, 10) - startUnix;
  270. $('#ov-operation').text(ao_module_utils.durationConverter(newOprTime));
  271. accumulateOperationTime();
  272. }, 1000);
  273. }
  274. window.ovLogout = function () {
  275. if (window.parent && typeof window.parent.logout === 'function') {
  276. window.parent.logout();
  277. return;
  278. }
  279. if (typeof logout === 'function') {
  280. logout();
  281. }
  282. };
  283. applyTheme();
  284. overviewLocale.init('../locale/system_settings/overview.json', function () {
  285. overviewLocale.translate();
  286. initHostInfo();
  287. initUserInfo();
  288. initStorageInfo();
  289. initHomepageState();
  290. initRuntimeInfo();
  291. });
  292. })();
  293. </script>