#260: static button width during copy feedback (fix attempt 2) #272

Closed
fen wants to merge 1 commits from fix-260 into dev
4 changed files with 15 additions and 17 deletions
Showing only changes of commit c32566979f - Show all commits
+8
View File
@@ -580,6 +580,14 @@ a.admin-link:hover { color: var(--fg); text-decoration: underline; }
outline-offset: 1px;
}
/* swapbtn (#260): the label and the checkmark occupy the same grid cell, so
toggling feedback never changes the button's width — no pinning needed */
.swapbtn { display: inline-grid; }
.swapbtn > * { grid-area: 1 / 1; }
.swapbtn .btn-check { visibility: hidden; }
.swapbtn.ok .btn-check { visibility: visible; }
.swapbtn.ok .btn-label { visibility: hidden; }
/* in-place copy success feedback (#53) */
.iconbtn.ok, .btn.ok {
color: var(--ok);
+2 -6
View File
@@ -192,18 +192,14 @@ async function create() {
// button, password auto-unlock, then redirect to the paste.
function finishCreate(data) {
const url = location.origin + '/' + (data.custom_slug || data.id);
showResult('<a href="' + url + '">' + url + '</a> <button class="btn btn-icon" id="result-copy" title="Copy URL" type="button"></button>', 'ok');
showResult('<a href="' + url + '">' + url + '</a> <button class="btn btn-icon swapbtn" id="result-copy" title="Copy URL" type="button"><span class="btn-label">⧉</span><span class="btn-check">✓</span></button>', 'ok');
$('result').dataset.token = data.deletion_token || '';
const copyBtn = document.getElementById('result-copy');
copyBtn.addEventListener('click', () => {
try {
navigator.clipboard.writeText(url);
copyBtn.classList.add('ok'); // in-place success feedback (#53)
// #260: pin the pre-swap width so the wider/narrower glyph never
// shifts neighbouring elements; release it when the label restores.
copyBtn.style.minWidth = Math.ceil(copyBtn.getBoundingClientRect().width) + 'px';
copyBtn.textContent = '✓';
setTimeout(() => { copyBtn.classList.remove('ok'); copyBtn.textContent = '⧉'; copyBtn.style.minWidth = ''; }, 2000);
setTimeout(() => copyBtn.classList.remove('ok'), 2000);
} catch(e) { toast('Copy failed', 'error'); }
});
// token carried via sessionStorage, never in the URL (#143)
+3 -9
View File
@@ -18,17 +18,11 @@ function toggleStats() {
}
function copyFeedback(btn) {
if (!btn) return;
if (!btn.dataset.label) btn.dataset.label = btn.textContent; // remember the original label (Copy/Link)
// #260: keep the button width static during the feedback so surrounding
// elements never jump. Pin the pre-swap width, release it on restore.
if (!btn.dataset.pinned) {
btn.style.minWidth = Math.ceil(btn.getBoundingClientRect().width) + 'px';
btn.dataset.pinned = '1';
}
// #260: the .swapbtn grid stacks label + checkmark in one cell, so the
// width is static by construction — feedback is a pure class toggle.
btn.classList.add('ok');
btn.textContent = '✓';
clearTimeout(btn._okh);
btn._okh = setTimeout(() => { btn.classList.remove('ok'); btn.textContent = btn.dataset.label; }, 2000);
btn._okh = setTimeout(() => btn.classList.remove('ok'), 2000);
}
function copyContent(btn) {
navigator.clipboard.writeText(document.getElementById('raw-content').value)
+2 -2
View File
@@ -8,8 +8,8 @@
<div class="spacer"></div>
<button type="button" class="iconbtn wrap-toggle" title="Toggle line wrap" aria-pressed="false">Wrap</button>
<a class="iconbtn" href="/raw/{{.ID}}">Raw</a>
<a class="iconbtn" href="#" id="copy-link-btn">Link</a>
<a class="iconbtn" href="#" id="copy-btn">Copy</a>
<a class="iconbtn swapbtn" href="#" id="copy-link-btn"><span class="btn-label">Link</span><span class="btn-check"></span></a>
<a class="iconbtn swapbtn" href="#" id="copy-btn"><span class="btn-label">Copy</span><span class="btn-check"></span></a>
{{if .DeletionToken}}<a class="iconbtn danger" href="#" id="delete-btn">Delete</a>{{end}}
</div>
</div>