perf(comments): lazy-render top-level reply forms

The reply form used to render ~13 lines of hidden markup under every
top-level comment, so a 50-comment video shipped roughly 650 lines of
inert DOM to every signed-in viewer. Replaced with a single
<template id="ytc-reply-form-tpl"> plus a per-comment slot div; the
first click on Reply clones the template, wires the IDs
(replyForm{id}, replyBody{id}, data-parent-id, data-video-id) and
appends it, so toggle behavior stays identical from the user's side.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
ghassanandClaude Opus 4.7 committed 2026-10-21 00:52:13 +03:00
1 parent 8fdac4b483
commit 8aa08e705a
1 file changed
+46 -16
@@ -156,20 +156,12 @@
@endif @endif
</div> </div>
{{-- Reply form --}} {{-- Reply form is lazy-cloned from #ytc-reply-form-tpl on
first click; the ~13-line markup used to render for
every top-level comment (so a 50-comment video shipped
~650 lines of hidden form markup to every viewer). --}}
@auth @auth
<div class="ytc-reply-form" id="replyForm{{ $comment->id }}"> <div class="ytc-reply-slot" data-comment-id="{{ $comment->id }}" data-video-id="{{ $video->getRouteKey() }}"></div>
<img src="{{ Auth::user()->avatar_url }}" class="ytc-avatar ytc-avatar-sm" alt="{{ Auth::user()->name }}">
<div class="ytc-input-wrap">
<textarea class="ytc-textarea ytc-reply-textarea" id="replyBody{{ $comment->id }}"
placeholder="Add a reply..." rows="1"></textarea>
<div class="ytc-form-actions">
<button class="ytc-btn ytc-btn-cancel _comment-cancel-reply-trigger" data-comment-id="{{ $comment->id }}">Cancel</button>
<button class="ytc-btn ytc-btn-submit _comment-submit-reply-trigger"
data-video-id="{{ $video->getRouteKey() }}" data-parent-id="{{ $comment->id }}">Reply</button>
</div>
</div>
</div>
@endauth @endauth
{{-- Replies --}} {{-- Replies --}}
@@ -1062,10 +1054,29 @@ async function toggleTranslate(btn) {
} }
} }
// ── Reply form ──────────────────────────────────────── // ── Reply form (lazy-rendered from a <template>) ──────
// Replaces the per-comment inline markup that used to live in the DOM
// pre-hidden. First click on "Reply" clones the template into the comment's
// .ytc-reply-slot and wires its IDs. Subsequent toggles just show/hide.
function toggleReplyForm(commentId) { function toggleReplyForm(commentId) {
const form = document.getElementById('replyForm' + commentId); let form = document.getElementById('replyForm' + commentId);
if (!form) return; if (!form) {
const slot = document.querySelector('.ytc-reply-slot[data-comment-id="' + commentId + '"]');
const tpl = document.getElementById('ytc-reply-form-tpl');
if (!slot || !tpl) return;
const frag = tpl.content.cloneNode(true);
const root = frag.querySelector('.ytc-reply-form');
const ta = frag.querySelector('.ytc-reply-textarea');
const cancel = frag.querySelector('._comment-cancel-reply-trigger');
const submit = frag.querySelector('._comment-submit-reply-trigger');
root.id = 'replyForm' + commentId;
ta.id = 'replyBody' + commentId;
cancel.dataset.commentId = commentId;
submit.dataset.parentId = commentId;
submit.dataset.videoId = slot.dataset.videoId || YTC.videoId;
slot.appendChild(frag);
form = root;
}
const isOpen = form.classList.contains('open'); const isOpen = form.classList.contains('open');
document.querySelectorAll('.ytc-reply-form.open').forEach(f => f.classList.remove('open')); document.querySelectorAll('.ytc-reply-form.open').forEach(f => f.classList.remove('open'));
if (!isOpen) { if (!isOpen) {
@@ -1513,3 +1524,22 @@ window._comment = {
})(); })();
</script> </script>
@auth
{{-- Reply-form template. Cloned into .ytc-reply-slot the first time a user
clicks Reply on a given comment. Keeping it here (not in the layout)
means the markup travels with the comments component — the only place
that uses it. --}}
<template id="ytc-reply-form-tpl">
<div class="ytc-reply-form">
<img src="{{ Auth::user()->avatar_url }}" class="ytc-avatar ytc-avatar-sm" alt="{{ Auth::user()->name }}">
<div class="ytc-input-wrap">
<textarea class="ytc-textarea ytc-reply-textarea" placeholder="Add a reply..." rows="1"></textarea>
<div class="ytc-form-actions">
<button class="ytc-btn ytc-btn-cancel _comment-cancel-reply-trigger">Cancel</button>
<button class="ytc-btn ytc-btn-submit _comment-submit-reply-trigger">Reply</button>
</div>
</div>
</div>
</template>
@endauth