openvibers/openvibe.live Commits

Content: New paste opens the paste form (its header button never reached the feed's controls), and the paste box is 240px tall again (#416)

OP OpenVibers committed 17 days ago · 0bdb5f4887 · 3 files, +41 −4

The owner, on a phone (2026-10-27): "This button does nothing." The feed listened for clicks on its filter bar only,
and New paste sits in the header beside AI Moments. A failed feature load now lands on /pastes. textarea.form-input's
60px minimum also beat .paste-textarea's 240px, so the box showed two lines.

Changes

ddiff --git a/public/css/style.css b/public/css/style.css
iindex 751a8361..8b7b6598 100644
---- a/public/css/style.css
++++ b/public/css/style.css
@@@ -6578,7 +6578,8 @@ body.theme-light .btn-outline:hover {
justify-content: flex-end;
gap: 8px;
}
--.paste-textarea {
++/* textarea.* beats `textarea.form-input`'s 60px minimum, which had shrunk the paste box to two lines (2026-10-27). */
++textarea.paste-textarea {
min-height: 240px;
resize: vertical;
font-family: 'Fira Code', 'Cascadia Code', 'JetBrains Mono', monospace;
ddiff --git a/public/js/content-feed.js b/public/js/content-feed.js
iindex b3c795fb..bbd1ba20 100644
---- a/public/js/content-feed.js
++++ b/public/js/content-feed.js
@@@ -471,8 +471,9 @@
else if (b.dataset.cfSort && b.dataset.cfSort !== S.sort) { S.sort = b.dataset.cfSort === 'top' ? 'top' : 'new'; refilter(); }
else if (b.dataset.cfWindow && b.dataset.cfWindow !== S.win && WINDOWS.includes(b.dataset.cfWindow)) { S.win = b.dataset.cfWindow; refilter(); }
else if (b.hasAttribute('data-cf-new-paste')) {
-- const go = () => { if (typeof openNewPasteModal === 'function') openNewPasteModal(); };
-- if (window.ov) ov.load('pastes').then(go, () => {}); else go();
++ // The paste form comes with the pastes feature; should it fail to load, the pastes page has the form too.
++ const go = () => { if (typeof openNewPasteModal === 'function') openNewPasteModal(); else if (typeof navigate === 'function') navigate('/pastes'); };
++ if (window.ov) ov.load('pastes').then(go, go); else go();
}
}
@@@ -518,7 +519,10 @@
scope.listen(st.feedEl, 'click', onFeedClick);
scope.listen(wrap.querySelector('.cf-head'), 'click', (e) => {
const a = e.target.closest('a[data-cf-link]');
-- if (a && typeof handleLinkClick === 'function') handleLinkClick(e, a.getAttribute('href'));
++ if (a) { if (typeof handleLinkClick === 'function') handleLinkClick(e, a.getAttribute('href')); return; }
++ // New paste sits in the header beside AI Moments, outside the filter bar: its button goes through the same
++ // controls (only .cf-bar was listened to, so it did nothing, owner 2026-10-27).
++ onControl(e);
});
let resizeRaf = 0;
scope.listen(window, 'resize', () => { cancelAnimationFrame(resizeRaf); resizeRaf = requestAnimationFrame(relayout); }, { passive: true });
ddiff --git a/test/content-new-paste.test.js b/test/content-new-paste.test.js
nnew file mode 100644
iindex 00000000..b918c8aa
---- /dev/null
++++ b/test/content-new-paste.test.js
@@@ -0,0 +1,32 @@
++/**
++ * The Content page's "New paste" (owner, 2026-10-27: "This button does nothing."). The button sits in the page header,
++ * beside AI Moments, outside the filter bar the feed listened to, so its taps never reached the feed's controls; and the
++ * paste box was shrunk to two lines by `textarea.form-input`'s 60px minimum.
++ *
++ * node test/content-new-paste.test.js
++ */
++'use strict';
++const assert = require('assert');
++const fs = require('fs');
++const path = require('path');
++
++const read = (f) => fs.readFileSync(path.join(__dirname, '..', f), 'utf8');
++const feed = read('public/js/content-feed.js');
++const fragment = read('public/fragments/content.html');
++
++// The button is in the header, and the header's clicks go through the same controls as the filter bar's.
++const head = fragment.slice(fragment.indexOf('<header class="cf-head">'), fragment.indexOf('</header>'));
++assert.ok(head.includes('data-cf-new-paste'), 'New paste sits in the header');
++const headListener = /scope\.listen\(wrap\.querySelector\('\.cf-head'\), 'click', \(e\) => \{[\s\S]*?\n {8}\}\);/.exec(feed);
++assert.ok(headListener, 'the header has a click listener');
++assert.ok(/onControl\(e\);/.test(headListener[0]), 'its clicks reach onControl, which opens the paste form');
++assert.ok(feed.includes("if (window.ov) ov.load('pastes').then(go, go); else go();"), 'a failed feature load still lands on the paste form (the pastes page)');
++
++// The paste box keeps its 240px: a selector at least as specific as textarea.form-input, and later in the file.
++const css = read('public/css/style.css');
++const generic = css.indexOf('textarea.form-input { resize: vertical; min-height: 60px; }');
++const paste = css.indexOf('textarea.paste-textarea {');
++assert.ok(generic > -1 && paste > generic, 'textarea.paste-textarea comes after textarea.form-input');
++assert.ok(/textarea\.paste-textarea \{\s*min-height: 240px;/.test(css));
++
++console.log('content new paste: all checks passed');