diff --git a/internal/api/cookie_set_test.go b/internal/api/cookie_set_test.go index 7311560..9da605e 100644 --- a/internal/api/cookie_set_test.go +++ b/internal/api/cookie_set_test.go @@ -91,7 +91,15 @@ func TestCreatedBannerViaCookie(t *testing.T) { if rec2.Code != 200 { t.Fatalf("paste view: got %d", rec2.Code) } - if !strings.Contains(rec2.Body.String(), tok) { - t.Error("created banner does not show the deletion token (#143 cookie flow broken)") + // #168: the created pill no longer prints the deletion token; the token + // still arrives via the one-time cookie flow (re-set on the view response). + var got bool + for _, c := range rec2.Result().Cookies() { + if c.Name == "tok_"+id && c.Value == tok { + got = true + } + } + if !got { + t.Error("created view did not re-set the deletion token cookie (#143 cookie flow broken)") } } diff --git a/internal/web/static/app.css b/internal/web/static/app.css index 2e0b0ee..ca1c7cd 100644 --- a/internal/web/static/app.css +++ b/internal/web/static/app.css @@ -197,11 +197,17 @@ body { border: 1px solid var(--border); border-radius: var(--radius); padding: 5px 8px; background: var(--bg); color: var(--fg); font: inherit; font-size: 21.6px; width: 130px; } -.created-banner { - display: none; padding: 10px 16px; font-size: 22.4px; background: var(--surface-2); - border-bottom: 1px solid var(--border); word-break: break-all; +/* #168: compact corner notification pill (paste-created feedback) */ +.created-pill { + position: fixed; right: 16px; bottom: 16px; z-index: 200; + background: var(--surface-2); color: var(--ok); border: 1px solid var(--ok); + border-radius: var(--radius-sm); padding: 4px 12px; font-size: 13px; + opacity: 0; pointer-events: none; transform: translateY(6px); + transition: opacity .25s ease, transform .25s ease; + box-shadow: 0 4px 16px rgba(0,0,0,.25); } -.created-banner a { color: var(--accent); } +.created-pill.show { opacity: 1; transform: translateY(0); } +@media (max-width: 640px) { .created-pill { right: 12px; bottom: 12px; } } /* paste view */ .meta-bar { display: flex; align-items: center; gap: 12px; padding: 12px 18px; flex-wrap: wrap; } @@ -386,15 +392,15 @@ td a.slug.paste-name { background: none; padding: 0; border-radius: 0; font-fami } .seg input, .toggle input { accent-color: var(--accent); width: 16px; height: 16px; margin: 0; } -/* toast (#19) */ +/* toast (#19, #168): small pill anchored to the corner, out of content flow */ .toast { - position: fixed; left: 50%; bottom: 32px; transform: translateX(-50%) translateY(8px); + position: fixed; right: 16px; bottom: 16px; background: var(--surface-2); color: var(--fg); border: 1px solid var(--border); - border-radius: var(--radius-sm); padding: 6px 18px; font-size: 20.7px; + border-radius: var(--radius-sm); padding: 6px 12px; font-size: 13px; opacity: 0; pointer-events: none; transition: opacity .25s ease, transform .25s ease; z-index: 200; box-shadow: 0 4px 16px rgba(0,0,0,.25); } -.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); } +.toast.show { opacity: 1; transform: translateY(0); } /* status variants (#16) */ .toast.success { border-color: var(--ok); color: var(--ok); } .toast.error { border-color: var(--err); color: var(--err); } @@ -623,7 +629,6 @@ a.admin-link:hover { color: var(--fg); text-decoration: underline; } .code { font-size: 13px; } .codebody { padding: 0 12px; } .footnote { font-size: 12px; padding: 8px 12px; gap: 10px; } - .created-banner { font-size: 13px; } .iconbtn { font-size: 13px; padding: 6px 10px; } /* unlock card */ @@ -802,4 +807,3 @@ button[type="submit"]:focus-visible, .mt18 { margin-top: 18px; } .toggle-inline { display: inline-flex; } .wrap-normal { word-break: normal; overflow-wrap: break-word; } -.created-banner.show { display: block; } diff --git a/internal/web/static/paste.js b/internal/web/static/paste.js index e5350e7..30a8842 100644 --- a/internal/web/static/paste.js +++ b/internal/web/static/paste.js @@ -42,6 +42,13 @@ var PASTE_ID = document.currentScript.getAttribute('data-paste-id'); var copyBtn = document.getElementById('copy-btn'); if (copyBtn) copyBtn.addEventListener('click', function (e) { e.preventDefault(); copyContent(copyBtn); }); var delBtn = document.getElementById('delete-btn'); + +// #168: show the compact paste-created pill in the bottom corner, then fade it out +const createdPill = document.getElementById('created-pill'); +if (createdPill) { + requestAnimationFrame(() => createdPill.classList.add('show')); + setTimeout(() => createdPill.classList.remove('show'), 4000); +} if (delBtn) delBtn.addEventListener('click', function (e) { e.preventDefault(); redeem(); }); var statsToggle = document.getElementById('stats-toggle'); if (statsToggle) statsToggle.addEventListener('click', toggleStats); diff --git a/internal/web/templates/new.html b/internal/web/templates/new.html index 9333744..d1d5bad 100644 --- a/internal/web/templates/new.html +++ b/internal/web/templates/new.html @@ -28,7 +28,6 @@ -
Ctrl+Enter to create
diff --git a/internal/web/templates/paste.html b/internal/web/templates/paste.html index fde0251..2a2d653 100644 --- a/internal/web/templates/paste.html +++ b/internal/web/templates/paste.html @@ -34,12 +34,7 @@
{{if .JustCreated}} -
-
- Paste created. Link copied to clipboard: {{.Host}}/{{.ID}} - {{if .DeletionToken}} · deletion token: {{.DeletionToken}}{{end}} -
-
+
Paste Created · Link Copied
{{end}} {{if .Attachment}}
diff --git a/internal/web/web.go b/internal/web/web.go index b502a4d..0f87e16 100644 --- a/internal/web/web.go +++ b/internal/web/web.go @@ -352,7 +352,7 @@ func (h *Handlers) HandlePasteView(w http.ResponseWriter, r *http.Request) { token = c.Value } if justCreated && token != "" { - // one-time display of the deletion token via the created banner + // one-time display of the deletion token via sessionStorage (#143) http.SetCookie(w, &http.Cookie{Name: "tok_" + row.ID, Value: token, Path: "/", MaxAge: 60, HttpOnly: true, SameSite: http.SameSiteLaxMode}) } // Count the view for real page renders, deduped per-viewer within the