diff --git a/internal/server/web/static/app.css b/internal/server/web/static/app.css index 7fbad7b..6c5bbe5 100644 --- a/internal/server/web/static/app.css +++ b/internal/server/web/static/app.css @@ -246,3 +246,16 @@ input.sw:disabled { opacity: .45; cursor: not-allowed; } table.stack td.actions { width: auto; padding-top: 8px; justify-content: flex-start; } table.stack td:empty { display: none; } } + +/* Scrollbars as on a Mac: thin, no track, seen only while scrolling or with + the pointer at the edge, then fading out (scroll.js sets --sb from 0 to 1). + Nothing to scroll, nothing shown. */ +* { --sb: 0; } +::-webkit-scrollbar { width: 8px; height: 8px; background: transparent; } +::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background: transparent; } +::-webkit-scrollbar-thumb { border-radius: 4px; border: 2px solid transparent; background-clip: padding-box; + background-color: rgba(170, 180, 195, calc(var(--sb) * .5)); } +::-webkit-scrollbar-thumb:hover { background-color: rgba(170, 180, 195, calc(var(--sb) * .75)); } +@supports not selector(::-webkit-scrollbar) { + * { scrollbar-width: thin; scrollbar-color: rgba(170, 180, 195, calc(var(--sb) * .5)) transparent; } +} diff --git a/internal/server/web/static/scroll.js b/internal/server/web/static/scroll.js new file mode 100644 index 0000000..9930777 --- /dev/null +++ b/internal/server/web/static/scroll.js @@ -0,0 +1,54 @@ +// Mac-like scrollbars: a scrolled element shows its thin scrollbar, and so +// does one whose edge the pointer is at; after a second at rest it fades out. +// Elements with nothing to scroll never show one. The look is in app.css. +(function () { + 'use strict'; + var live = new Map(); // element -> {v: shown 0..1, until: ms to stay} + var raf = 0; + function el(t) { return t === document || t === window ? document.documentElement : t; } + function scrollable(e) { + return e.scrollHeight > e.clientHeight + 1 || e.scrollWidth > e.clientWidth + 1; + } + function show(e, ms) { + if (!e || !e.style || !scrollable(e)) return; + var s = live.get(e) || {v: 0, until: 0}; + s.until = Math.max(s.until, performance.now() + ms); + live.set(e, s); + if (!raf) raf = setTimeout(tick, 16); + } + var last = 0; + // A timer, not animation frames: those stop in a tab out of sight, and the + // bar would stay shown. + function tick() { + var now = performance.now(); + var dt = Math.min(64, now - (last || now - 16)); + last = now; + live.forEach(function (s, e) { + // In fast (about 0.12 s), out slowly (about 0.4 s). + var want = now < s.until ? 1 : 0; + s.v = want ? Math.min(1, s.v + dt / 120) : Math.max(0, s.v - dt / 400); + e.style.setProperty('--sb', s.v.toFixed(3)); + if (!want && s.v === 0) { e.style.removeProperty('--sb'); live.delete(e); } + }); + raf = live.size ? setTimeout(tick, 16) : 0; + if (!raf) last = 0; + } + document.addEventListener('scroll', function (ev) { show(el(ev.target), 900); }, {capture: true, passive: true}); + // The pointer at a scrollable element's right or bottom edge shows its bar. + var moved = null; + document.addEventListener('pointermove', function (ev) { + if (ev.pointerType !== 'mouse') return; + if (!moved) requestAnimationFrame(function () { + var m = moved; moved = null; + for (var e = m.target; e && e.nodeType === 1; e = e.parentElement) { + if (!scrollable(e)) continue; + var st = getComputedStyle(e); + if (!/(auto|scroll)/.test(st.overflowY + st.overflowX) && e !== document.documentElement) continue; + var r = e === document.documentElement ? {right: innerWidth, bottom: innerHeight} : e.getBoundingClientRect(); + if (m.x >= r.right - 14 || m.y >= r.bottom - 14) show(e, 700); + break; + } + }); + moved = {target: ev.target, x: ev.clientX, y: ev.clientY}; + }, {passive: true}); +})(); diff --git a/internal/server/web/static/terminal.js b/internal/server/web/static/terminal.js index aaef8e4..ed8a8c7 100644 --- a/internal/server/web/static/terminal.js +++ b/internal/server/web/static/terminal.js @@ -10,8 +10,6 @@ const touch = matchMedia('(pointer: coarse)').matches; const desk = !touch; // drag and drop, splits: computers only if (touch) document.body.classList.add('touch'); - const ua = (navigator.userAgentData && navigator.userAgentData.platform) || navigator.platform || navigator.userAgent; - if (/^Win/i.test(ua) || /Windows/.test(navigator.userAgent)) document.body.classList.add('win'); const $ = id => document.getElementById(id); const statusEl = $('status'), area = $('area'), tablist = $('tablist'), addBtn = $('tabadd'), floatAdd = $('floatadd'), addMenu = $('addmenu'), hint = $('hint'), mark = $('tabmark'); diff --git a/internal/server/web/templates/dashboard.html b/internal/server/web/templates/dashboard.html index 85d6629..239a84d 100644 --- a/internal/server/web/templates/dashboard.html +++ b/internal/server/web/templates/dashboard.html @@ -6,6 +6,7 @@ Машины - LPRA +
diff --git a/internal/server/web/templates/edit.html b/internal/server/web/templates/edit.html index 9c48aae..8113714 100644 --- a/internal/server/web/templates/edit.html +++ b/internal/server/web/templates/edit.html @@ -6,6 +6,7 @@ Изменить машину - LPRA +
diff --git a/internal/server/web/templates/files.html b/internal/server/web/templates/files.html index 62777e1..b5a9a82 100644 --- a/internal/server/web/templates/files.html +++ b/internal/server/web/templates/files.html @@ -6,6 +6,7 @@ Файлы · {{.Agent.Name}} - LPRA +