Fix Quill link tooltip positioning and registration flash

Quill tooltip: move tooltip element to document.body via patchQuillTooltip()
so overflow:hidden on .cms-main cannot clip it. Recalculates position from
container-relative to viewport (fixed) coordinates with viewport clamping.
Removes overflow:hidden from quill wrappers; applies border-radius to toolbar/container.

Registration: hide #show-register by default in HTML; reveal only after
registration-status fetch confirms enabled=true. Endpoint already returns 403
when disabled — no backend change needed.
This commit is contained in:
Daniel Onyejesi 2026-03-23 23:09:21 -04:00
parent d0299f5284
commit 8aa1c5d0f7
4 changed files with 48 additions and 11 deletions

View file

@ -661,9 +661,10 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(--
}
/* ── Quill editor overrides ───────────────────────────────── */
.cms-quill-body{border:1px solid var(--g300);border-radius:8px;overflow:hidden;background:white;}
.cms-quill-body .ql-toolbar{border:none;border-bottom:1px solid var(--g200);background:var(--g50);border-radius:0;padding:8px;}
.cms-quill-body .ql-container{border:none;font-family:'Inter',system-ui,sans-serif;font-size:14px;}
/* No overflow:hidden on wrappers — tooltip must be able to escape the container */
.cms-quill-body{border:1px solid var(--g300);border-radius:8px;background:white;position:relative;}
.cms-quill-body .ql-toolbar{border:none;border-bottom:1px solid var(--g200);background:var(--g50);border-radius:8px 8px 0 0;padding:8px;}
.cms-quill-body .ql-container{border:none;font-family:'Inter',system-ui,sans-serif;font-size:14px;border-radius:0 0 8px 8px;}
.cms-quill-body .ql-editor{min-height:280px;padding:16px;}
.cms-quill-body .ql-editor p{margin-bottom:8px;}
.cms-quill-body .ql-editor h2{font-size:20px;font-weight:700;margin:16px 0 8px;}
@ -671,13 +672,16 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(--
.cms-quill-body .ql-editor blockquote{border-left:4px solid var(--blue);padding-left:12px;color:var(--g600);margin:10px 0;}
.cms-quill-body .ql-editor pre{background:var(--g900);color:#e5e7eb;padding:12px;border-radius:6px;font-size:13px;overflow-x:auto;}
/* Quill tooltip is moved to document.body by JS — just needs z-index */
.ql-tooltip{z-index:10000 !important;}
/* Mini quill on questions/options */
.lh-q-richtext-wrap{border:1.5px solid var(--g300);border-radius:8px;overflow:hidden;margin-bottom:8px;}
.lh-q-richtext-wrap .ql-toolbar{border:none;border-bottom:1px solid var(--g200);background:var(--g50);padding:4px 6px;}
.lh-q-richtext-wrap{border:1.5px solid var(--g300);border-radius:8px;margin-bottom:8px;position:relative;}
.lh-q-richtext-wrap .ql-toolbar{border:none;border-bottom:1px solid var(--g200);background:var(--g50);padding:4px 6px;border-radius:8px 8px 0 0;}
.lh-q-richtext-wrap .ql-container{border:none;font-size:14px;font-family:'Inter',system-ui,sans-serif;}
.lh-q-richtext-wrap .ql-editor{min-height:60px;padding:10px;}
.lh-opt-richtext-wrap{border:1.5px solid var(--g300);border-radius:6px;overflow:hidden;flex:2;}
.lh-opt-richtext-wrap .ql-toolbar{border:none;border-bottom:1px solid var(--g200);background:var(--g50);padding:2px 4px;}
.lh-opt-richtext-wrap{border:1.5px solid var(--g300);border-radius:6px;flex:2;position:relative;}
.lh-opt-richtext-wrap .ql-toolbar{border:none;border-bottom:1px solid var(--g200);background:var(--g50);padding:2px 4px;border-radius:6px 6px 0 0;}
.lh-opt-richtext-wrap .ql-container{border:none;font-size:13px;font-family:'Inter',system-ui,sans-serif;}
.lh-opt-richtext-wrap .ql-editor{min-height:40px;padding:6px 8px;}

View file

@ -53,7 +53,7 @@
</div>
<button type="submit" class="btn-auth">Sign In</button>
<div class="auth-links">
<a href="#" id="show-register">Create account</a>
<a href="#" id="show-register" style="display:none">Create account</a>
<a href="#" id="show-forgot">Forgot password?</a>
</div>
</form>

View file

@ -414,13 +414,13 @@ document.addEventListener('DOMContentLoaded', function() {
// Expose globally so app.js tabChanged handler can call it
window.load2FAStatus = load2FAStatus;
// Check registration status
// Check registration status — link is hidden by default, shown only when enabled
fetch('/api/auth/registration-status')
.then(function(r) { return r.json(); })
.then(function(data) {
if (!data.registrationEnabled) {
if (data.registrationEnabled) {
var link = document.getElementById('show-register');
if (link) link.style.display = 'none';
if (link) link.style.display = '';
}
})
.catch(function() {});

View file

@ -581,6 +581,37 @@
renderCmsContentList(filtered);
}
// ── Quill tooltip fix ─────────────────────────────────────
// Moves the tooltip element to document.body so overflow:hidden on
// ancestor containers cannot clip it. Recalculates position to
// viewport (fixed) coordinates on every show.
function patchQuillTooltip(q) {
var tooltip = q && q.theme && q.theme.tooltip;
if (!tooltip || !tooltip.root) return;
var el = tooltip.root;
document.body.appendChild(el);
el.style.position = 'fixed';
el.style.zIndex = '10000';
var origPosition = tooltip.position.bind(tooltip);
tooltip.position = function(reference) {
origPosition(reference);
// Quill sets left/top as container-relative; convert to viewport coords
var rect = q.container.getBoundingClientRect();
var l = rect.left + parseFloat(el.style.left || 0);
var t = rect.top + parseFloat(el.style.top || 0);
// Clamp to viewport
var tw = el.offsetWidth || 200;
var th = el.offsetHeight || 40;
if (l + tw > window.innerWidth - 8) l = window.innerWidth - tw - 8;
if (l < 8) l = 8;
if (t + th > window.innerHeight - 8) t = rect.top + parseFloat(el.style.top || 0) - th - 8;
if (t < 8) t = 8;
el.style.left = l + 'px';
el.style.top = t + 'px';
};
}
// ── Quill body editor ─────────────────────────────────────
function initBodyEditor() {
var container = document.getElementById('lh-body-editor');
@ -599,6 +630,7 @@
]
}
});
patchQuillTooltip(_bodyQuill);
}
// Mini Quill for question text or option text
@ -610,6 +642,7 @@
theme: 'snow',
modules: { toolbar: toolbar }
});
patchQuillTooltip(q);
if (existingHtml) q.clipboard.dangerouslyPasteHTML(existingHtml);
return q;
}