diff --git a/internal/server/web/static/app.css b/internal/server/web/static/app.css index a4d74f1..d8e1df3 100644 --- a/internal/server/web/static/app.css +++ b/internal/server/web/static/app.css @@ -145,6 +145,18 @@ dialog { background: var(--panel); color: var(--text); border: 1px solid var(--b border-radius: 12px; padding: 0; max-width: 900px; width: 92vw; } dialog::backdrop { background: rgba(0, 0, 0, .6); } dialog:focus { outline: none; } +/* Dialogs come and go smoothly: rise and fade in, sink and fade out, the + backdrop with them. Browsers without the exit transition just close. */ +dialog { opacity: 0; transform: translateY(10px) scale(.97); + transition: opacity .2s ease, transform .2s ease, overlay .2s ease allow-discrete, display .2s ease allow-discrete; } +dialog[open] { opacity: 1; transform: none; } +dialog::backdrop { opacity: 0; transition: opacity .2s ease, overlay .2s ease allow-discrete, display .2s ease allow-discrete; } +dialog[open]::backdrop { opacity: 1; } +@starting-style { + dialog[open] { opacity: 0; transform: translateY(10px) scale(.97); } + dialog[open]::backdrop { opacity: 0; } +} +@media (prefers-reduced-motion: reduce) { dialog, dialog::backdrop { transition: none; } } .dlg-h { padding: 14px 18px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 10px; } .dlg-b { padding: 16px 18px; } /* The account button in the top bar, and its dialog. */ diff --git a/internal/server/web/static/terminal.js b/internal/server/web/static/terminal.js index 50f17e0..6b465f8 100644 --- a/internal/server/web/static/terminal.js +++ b/internal/server/web/static/terminal.js @@ -732,8 +732,8 @@ // then runs once the dialog is shut and focus is back where it was, so // what it focuses stays focused. function close(then) { - d.classList.add('closing'); - setTimeout(() => { d.classList.remove('closing'); d.close(); if (then) then(); }, 160); + d.close(); + if (then) then(); } d.addEventListener('cancel', ev => { ev.preventDefault(); close(); }); d.addEventListener('click', ev => { if (ev.target === d) close(); }); diff --git a/internal/server/web/templates/files.html b/internal/server/web/templates/files.html index 3d79792..f43485e 100644 --- a/internal/server/web/templates/files.html +++ b/internal/server/web/templates/files.html @@ -84,7 +84,6 @@ } dialog { background:var(--panel); color:var(--text); border:1px solid var(--border); border-radius:12px; padding:0; max-width:900px; width:92vw; } - dialog::backdrop { background:rgba(0,0,0,.6); } /* A dialog takes the focus itself when it opens, rather than its first button, which would light up as if tabbed to. */ dialog:focus { outline:none; } diff --git a/internal/server/web/templates/terminal.html b/internal/server/web/templates/terminal.html index b84bd31..37636f6 100644 --- a/internal/server/web/templates/terminal.html +++ b/internal/server/web/templates/terminal.html @@ -15,13 +15,6 @@ .badge-ssh { flex:none; font-size:10px; font-weight:600; letter-spacing:.04em; padding:1px 5px; border-radius:4px; background:#12202f; color:var(--accent); border:1px solid #1f3a57; } dialog.sshdlg { max-width:460px; } - dialog.sshdlg[open] { animation:dlg-in .2s ease; } - dialog.sshdlg[open]::backdrop { animation:dlg-fade .2s ease; } - dialog.sshdlg.closing { animation:dlg-out .16s ease forwards; } - dialog.sshdlg.closing::backdrop { animation:dlg-fade .16s ease reverse forwards; } - @keyframes dlg-in { from { opacity:0; transform:translateY(10px) scale(.97); } } - @keyframes dlg-out { to { opacity:0; transform:translateY(6px) scale(.98); } } - @keyframes dlg-fade { from { opacity:0; } } .sshdlg .dlg-h .ico { color:var(--accent); display:inline-flex; } .sshdlg .dlg-b { display:grid; gap:12px; } .sshdlg .f { display:grid; gap:5px; margin:0; }