diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 0b9c5b9..09b1aad 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -1458,6 +1458,21 @@ func (h *harness) postForm(t *testing.T, path string, form url.Values, cookie *h // The delete token is shown once and then has to be usable somewhere. The info // page is the link an uploader would have kept, so the form lives there. +// detailsIsOpen reports whether the page's first
is rendered open, +// by reading the attribute rather than matching the whole tag: the element +// carries classes too, and styling it must not be able to fail this. +func detailsIsOpen(page string) bool { + start := strings.Index(page, "") + if end < 0 { + return false + } + return strings.Contains(page[start:start+end], " open") +} + func TestInfoPageAcceptsTheDeleteToken(t *testing.T) { h := newHarness(t, nil) res := decode[uploadResult](t, h.upload(t, []byte("x"), nil)) @@ -1510,7 +1525,7 @@ func TestWrongDeleteTokenReturnsToTheInfoPage(t *testing.T) { if !strings.Contains(page, "not correct") { t.Error("the page does not say what went wrong") } - if !strings.Contains(page, "
") { + if !detailsIsOpen(page) { t.Error("the delete section is collapsed, hiding the error") } if _, err := h.store.Get(res.ID, h.now); err != nil { diff --git a/web/static/style.css b/web/static/style.css index 5e372a1..5adfd43 100644 --- a/web/static/style.css +++ b/web/static/style.css @@ -289,10 +289,36 @@ button.small { padding: .2rem .5rem; font-size: .75rem; } .cli code, .hint code { background: var(--bg); padding: .1rem .3rem; border-radius: 4px; } -/* One-off token, tucked away so the common path stays a single button. */ -.onceoff { margin-bottom: 1rem; } -.onceoff summary { font-weight: 400; font-size: .875rem; color: var(--muted); } -.onceoff .field { max-width: 24rem; } +/* Disclosure panels: the one-off token on the upload form, "Remove this file" + on the info page. Closed, a panel is a single line and needs nothing; open, + it needs an edge, or its contents read as loose page furniture and there is + no telling where it ends. */ +details.panel { + border: 1px solid var(--line); + border-radius: var(--radius); + margin-bottom: 1rem; +} +details.panel > summary { + padding: .625rem .75rem; + font-weight: 400; + font-size: .875rem; + color: var(--muted); + cursor: pointer; +} +details.panel[open] > summary { + border-bottom: 1px solid var(--line); + margin-bottom: .75rem; +} +/* The summary carries the panel's padding itself; everything else is inset to + match, and the panel closes the gap under the last of them. */ +details.panel > :not(summary) { padding-left: .75rem; padding-right: .75rem; } +details.panel[open] { padding-bottom: .75rem; } +details.panel > :last-child { margin-bottom: 0; } +details.panel .field { max-width: 24rem; } + +/* A hint that introduces a control is an instruction for what follows, not a + caption for what came before, so it must not sit against it. */ +.hint + form, .hint + .field { margin-top: .75rem; } .limits .hint { margin-top: .75rem; } .limits dl, .card dl { row-gap: .375rem; } diff --git a/web/templates/index.html b/web/templates/index.html index bb4c191..f0aaa41 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -23,7 +23,7 @@ -
+
Use a different token for this upload

Applies to this upload only and does not log you in. diff --git a/web/templates/info.html b/web/templates/info.html index 7af83a0..fa6c4e5 100644 --- a/web/templates/info.html +++ b/web/templates/info.html @@ -19,7 +19,7 @@

- +
Remove this file {{if .Error}}

{{.Error}}

{{end}}