Comments UI update (#11283)
* tooltips 1.0.1 * tooltips 1.0.1 * init * . * drop not needed files * . * init * init * . * comments * border * missing bits * build comment JS * . * . * specs * sloan avatar fix * bunch of fixes * specs and fixes * specs * . * swap order of links * contrast * js for dropdown * icons * op-author * three dots icon * reverts * test: capybara- make sure that we click the dropdown before clicking on edit * permalink --> link * tiny fixes * aria-label on form * proper alt on user's avatar * aria has popup * use UL > LI instead of DIV * add aria-labels to dropdown items * another aria-label * better links: nav * contrast Co-authored-by: Ridhwana <ridhwana.khan16@gmail.com>
This commit is contained in:
parent
fd8f83dc7d
commit
70706d0a62
41 changed files with 779 additions and 1322 deletions
3
app/assets/images/collapse.svg
Normal file
3
app/assets/images/collapse.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 10.677L8 6.935 9 6l3 2.807L15 6l1 .935-4 3.742zm0 4.517L9 18l-1-.935 4-3.742 4 3.742-1 .934-3-2.805z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 212 B |
3
app/assets/images/expand.svg
Normal file
3
app/assets/images/expand.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 18l-4-3.771 1-.943 3 2.829 3-2.829 1 .943L12 18zm0-10.115l-3 2.829-1-.943L12 6l4 3.771-1 .942-3-2.828z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 214 B |
3
app/assets/images/small-medal.svg
Normal file
3
app/assets/images/small-medal.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 8.25a6 6 0 110 12 6 6 0 010-12zm0 2.625l-.992 2.01-2.218.322 1.605 1.564-.379 2.21L12 15.937l1.984 1.043-.379-2.209 1.605-1.564-2.218-.323L12 10.875zm.75-6.376l3.75.001v2.25l-1.022.854a7.45 7.45 0 00-2.728-.817V4.5zm-1.5 0v2.288a7.451 7.451 0 00-2.727.816L7.5 6.75V4.5h3.75z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 386 B |
3
app/assets/images/small-overflow-horizontal.svg
Normal file
3
app/assets/images/small-overflow-horizontal.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.25 12a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zm5.25 0a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zm3.75 1.5a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 273 B |
3
app/assets/images/small-thread.svg
Normal file
3
app/assets/images/small-thread.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17 13l-5 6-5-6h3.125c0-3.314 2.798-6 6.25-6 .17 0 .34.006.506.02-1.787.904-3.006 2.705-3.006 4.78V13H17z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 213 B |
|
|
@ -131,7 +131,7 @@ function initializeCommentDropdown() {
|
|||
return;
|
||||
}
|
||||
|
||||
reportAbuseLink.innerHTML = `<a href="${reportAbuseLink.dataset.path}" class="crayons-link crayons-link--block">Report Abuse</a>`;
|
||||
reportAbuseLink.innerHTML = `<a href="${reportAbuseLink.dataset.path}" class="crayons-link crayons-link--block">Report abuse</a>`;
|
||||
}
|
||||
|
||||
function addDropdownListener(dropdown) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
var iconSmallThread = `<svg width="24" height="24" class="crayons-icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M17 13l-5 6-5-6h3.125c0-3.314 2.798-6 6.25-6 .17 0 .34.006.506.02-1.787.904-3.006 2.705-3.006 4.78V13H17z" /></svg>`;
|
||||
|
||||
function initializeCommentsPage() {
|
||||
if (document.getElementById('comments-container')) {
|
||||
toggleCodeOfConduct();
|
||||
|
|
@ -28,12 +30,22 @@ function initializeCommentsPage() {
|
|||
for (var i = 0; i < publicReactionCounts.length; i++) {
|
||||
var buttForComment = document.getElementById('button-for-comment-' + publicReactionCounts[i].id);
|
||||
if (buttForComment) {
|
||||
var reactionsCountWrapper = buttForComment.querySelector('.reactions-count');
|
||||
var reactionsLabelWrapper = buttForComment.querySelector('.reactions-label');
|
||||
if (publicReactionCounts[i].count > 0) {
|
||||
if (!document.getElementById('reactions-count-' + publicReactionCounts[i].id)) {
|
||||
buttForComment.innerHTML = buttForComment.innerHTML + "<span class='reactions-count' id='reactions-count-" + publicReactionCounts[i].id + "'>" + publicReactionCounts[i].count + '</span>';
|
||||
|
||||
if (publicReactionCounts[i].count > 1) {
|
||||
reactionsLabelWrapper.innerHTML = " likes";
|
||||
} else {
|
||||
document.getElementById('reactions-count-' + publicReactionCounts[i].id).innerHTML = publicReactionCounts[i].count;
|
||||
reactionsLabelWrapper.innerHTML = " like";
|
||||
}
|
||||
|
||||
reactionsCountWrapper.id = 'reactions-count-' + publicReactionCounts[i].id;
|
||||
reactionsCountWrapper.innerHTML = publicReactionCounts[i].count;
|
||||
reactionsCountWrapper.classList.remove("hidden");
|
||||
} else {
|
||||
reactionsCountWrapper.classList.add("hidden");
|
||||
reactionsCountWrapper.innerHTML = '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,14 +53,13 @@ function initializeCommentsPage() {
|
|||
for (var i = 0; i < allNodes.length; i++) {
|
||||
if (allNodes[i].dataset.commentAuthorId == responseObj.current_user.id) {
|
||||
allNodes[i].dataset.currentUserComment = "true";
|
||||
var userActionsEl = allNodes[i].children[0].children[2].children[0];
|
||||
var path = allNodes[i].dataset.path;
|
||||
var userActionsEl = allNodes[i].querySelector('.current-user-actions');
|
||||
var buttEl = document.getElementById('button-for-comment-' + allNodes[i].dataset.commentId);
|
||||
if (userActionsEl && buttEl) {
|
||||
userActionsEl.className = 'current-user-actions';
|
||||
userActionsEl.innerHTML = '<a data-no-instant href="' + userActionsEl.parentNode.dataset.path + '/delete_confirm" class="edit-butt">Delete</a>\
|
||||
<a href="' + userActionsEl.parentNode.dataset.path + '/edit">Edit</a>'
|
||||
userActionsEl.style.display = 'inline-block';
|
||||
document.getElementById('button-for-comment-' + allNodes[i].dataset.commentId).classList.add('reacted');
|
||||
userActionsEl.innerHTML = `<li><a href="${ path }/edit" class="crayons-link crayons-link--block" aria-label="Edit this comment">Edit</a></li>
|
||||
<li><a data-no-instant href="${ path }/delete_confirm" class="edit-butt crayons-link crayons-link--block" aria-label="Delete this comment">Delete</a></li>`
|
||||
userActionsEl.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -78,16 +89,27 @@ function initializeCommentsPage() {
|
|||
thisButt.disabled = true;
|
||||
|
||||
function successCb(response) {
|
||||
var reactionCountSpan = thisButt.children[2];
|
||||
var reactionCount = thisButt.querySelector('.reactions-count');
|
||||
var reactionLabel = thisButt.querySelector('.reactions-label');
|
||||
if (response.result === 'create') {
|
||||
thisButt.classList.add('reacted');
|
||||
if (reactionCountSpan) {
|
||||
reactionCountSpan.innerHTML = parseInt(reactionCountSpan.innerHTML) + 1;
|
||||
if (reactionCount) {
|
||||
reactionCount.innerHTML = parseInt(reactionCount.innerHTML) + 1;
|
||||
reactionCount.classList.remove("hidden");
|
||||
if(parseInt(reactionCount.innerHTML) == 1) {
|
||||
reactionLabel.innerHTML = " like"
|
||||
} else if(parseInt(reactionCount.innerHTML) > 1) {
|
||||
reactionLabel.innerHTML = " likes"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
thisButt.classList.remove('reacted');
|
||||
if (reactionCountSpan) {
|
||||
reactionCountSpan.innerHTML = parseInt(reactionCountSpan.innerHTML) - 1;
|
||||
if (reactionCount) {
|
||||
reactionCount.innerHTML = parseInt(reactionCount.innerHTML) - 1;
|
||||
if(parseInt(reactionCount.innerHTML) == 0) {
|
||||
reactionCount.classList.add("hidden");
|
||||
reactionLabel.innerHTML = "Like"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -117,13 +139,12 @@ function initializeCommentsPage() {
|
|||
showModal('reply-to-comment');
|
||||
return;
|
||||
}
|
||||
var actionNode = event.target.parentNode;
|
||||
var parentId = actionNode.dataset.commentId;
|
||||
var parentId = event.target.closest('.comment').dataset.commentId;
|
||||
var waitingOnCSRF = setInterval(function () {
|
||||
var metaTag = document.querySelector("meta[name='csrf-token']");
|
||||
if (metaTag) {
|
||||
clearInterval(waitingOnCSRF);
|
||||
commentWrapper = event.target.closest('.inner-comment');
|
||||
commentWrapper = event.target.closest('.comment__details');
|
||||
commentWrapper.classList.add("replying");
|
||||
commentWrapper.innerHTML += buildCommentFormHTML(commentableId, commentableType, parentId);
|
||||
initializeCommentsPage();
|
||||
|
|
@ -137,14 +158,7 @@ function initializeCommentsPage() {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
var editButts = document.getElementsByClassName('edit-butt');
|
||||
for (var i = 0; i < editButts.length; i++) {
|
||||
var butt = editButts[i];
|
||||
butt.onclick = function () {
|
||||
// event.preventDefault();
|
||||
// alert("edit clicked!")
|
||||
};
|
||||
}
|
||||
|
||||
if (document.getElementById('new_comment')) {
|
||||
document.getElementById('new_comment').addEventListener('submit', handleCommentSubmit);
|
||||
}
|
||||
|
|
@ -165,16 +179,6 @@ function toggleCodeOfConduct() {
|
|||
}
|
||||
}
|
||||
|
||||
function replaceActionButts(el) {
|
||||
var loggedInActionButts = "";
|
||||
var wrapper = el.getElementsByClassName("actions")[0]
|
||||
if (el.dataset.currentUserComment == "true") {
|
||||
loggedInActionButts = '<a data-no-instant href="' + el.parentNode.parentNode.dataset.path + '/delete_confirm" class="edit-butt">Delete</a>\
|
||||
<a href="' + el.parentNode.parentNode.dataset.path + '/edit">Edit</a>'
|
||||
}
|
||||
wrapper.innerHTML = '<span class="current-user-actions">' + loggedInActionButts + '</span><a href="#" class="toggle-reply-form">Reply</a>';
|
||||
}
|
||||
|
||||
function handleCommentSubmit(event) {
|
||||
event.preventDefault();
|
||||
var form = event.target;
|
||||
|
|
@ -219,10 +223,13 @@ function handleCommentSubmit(event) {
|
|||
var mainCommentsForm = document.getElementById("new_comment");
|
||||
if (parentComment) {
|
||||
handleFormClose(event);
|
||||
if (newComment.depth > 2) {
|
||||
parentComment.getElementsByClassName("toggle-reply-form")[0].innerHTML = ""
|
||||
if (newComment.depth > 3) {
|
||||
var replyTrigger = parentComment.getElementsByClassName("toggle-reply-form")[0];
|
||||
var threadIndicator = `<span class="fs-s inline-flex items-center fs-italic color-base-50 pl-1">${ iconSmallThread }Thread</span>`;
|
||||
replyTrigger.classList.replace("inline-flex", "hidden");
|
||||
replyTrigger.parentNode.innerHTML += threadIndicator;
|
||||
}
|
||||
var actionsNode = parentComment.getElementsByClassName("inner-comment")[0];
|
||||
var actionsNode = parentComment.getElementsByClassName("comment__inner")[0];
|
||||
actionsNode.parentNode.insertBefore(newNode, actionsNode.nextSibling);
|
||||
}
|
||||
|
||||
|
|
@ -496,19 +503,19 @@ function handleImageUpload(event, randomIdNumber) {
|
|||
}
|
||||
|
||||
function listenForDetailsToggle() {
|
||||
var detailItems = document.getElementsByTagName("DETAILS");
|
||||
var detailItems = document.querySelectorAll(".js-comment-wrapper");
|
||||
for (var i = 0; i < detailItems.length; i++) {
|
||||
detailItems[i].addEventListener("toggle", event => {
|
||||
var item = event.target
|
||||
var itemSummaryContent = item.getElementsByTagName("SPAN")[0]
|
||||
var usernames = item.getElementsByClassName("comment-username")
|
||||
var item = event.target;
|
||||
var itemSummaryContent = item.getElementsByClassName("js-collapse-comment-content")[0];
|
||||
var usernames = item.getElementsByClassName("js-comment-username");
|
||||
var number = "";
|
||||
if (usernames.length > 1) {
|
||||
number = " + " + (usernames.length - 1) + " replies"
|
||||
}
|
||||
var itemUsername = usernames[0].textContent + number
|
||||
if (item.open) {
|
||||
itemSummaryContent.innerHTML = " "
|
||||
itemSummaryContent.innerHTML = "";
|
||||
} else {
|
||||
itemSummaryContent.innerHTML = itemUsername;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ function buildCommentFormHTML(commentableId, commentableType, parentId) {
|
|||
<input value="${parentId}" type="hidden" name="comment[parent_id]" id="comment_parent_id" />
|
||||
<div class="comment-form__inner">
|
||||
<div class="comment-form__field">
|
||||
<textarea id="textarea-for-${parentId}" class="crayons-textfield crayons-textfield--ghost comment-textarea" name="comment[body_markdown]" placeholder="Reply..." required="required" onkeydown="handleKeyDown(event)" onfocus="handleFocus(event)" oninput="handleChange(event)" onkeykup="handleKeyUp(event)"></textarea>
|
||||
<textarea id="textarea-for-${parentId}" class="crayons-textfield crayons-textfield--ghost comment-textarea" name="comment[body_markdown]" placeholder="Reply..." aria-label="Reply to a comment..." required="required" onkeydown="handleKeyDown(event)" onfocus="handleFocus(event)" oninput="handleChange(event)" onkeykup="handleKeyUp(event)"></textarea>
|
||||
<div class="comment-form__toolbar">
|
||||
<div class="editor-image-upload">
|
||||
<input type="file" id="image-upload-${randomIdNumber}" name="file" accept="image/*" style="display:none">
|
||||
|
|
|
|||
|
|
@ -1,116 +1,138 @@
|
|||
function buildCommentHTML(comment) {
|
||||
var iconSmallOverflowHorizontal = `<svg width="24" height="24" viewBox="0 0 24 24" class="crayons-icon pointer-events-none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M8.25 12a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zm5.25 0a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zm3.75 1.5a1.5 1.5 0 100-3 1.5 1.5 0 000 3z" /></svg>`;
|
||||
var iconCollaspe = `<svg width="24" height="24" class="crayons-icon expanded" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 10.6771L8 6.93529L8.99982 6L12 8.80653L15.0002 6L16 6.93529L12 10.6771ZM12 15.1935L8.99982 18L8 17.0647L12 13.3229L16 17.0647L15.0002 17.9993L12 15.1935Z" /></svg>`;
|
||||
var iconExpand = `<svg width="24" height="24" class="crayons-icon collapsed" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 18L8 14.2287L8.99982 13.286L12 16.1147L15.0002 13.286L16 14.2287L12 18ZM12 7.88533L8.99982 10.714L8 9.77133L12 6L16 9.77133L15.0002 10.7133L12 7.88533Z" /></svg>`;
|
||||
|
||||
var depthClass = "";
|
||||
var githubIcon = "";
|
||||
var twitterIcon = "";
|
||||
var customClass = "";
|
||||
var detailsStartHTML = "";
|
||||
var detailsFinishHTML = "";
|
||||
var body = "";
|
||||
|
||||
if (!comment.newly_created) {
|
||||
depthClass="child flat-node"
|
||||
} else if (comment.depth == 0 ){
|
||||
depthClass = "root";
|
||||
} else if (comment.depth < 3) {
|
||||
depthClass="child"
|
||||
var detailsStartHTML = "";
|
||||
var detailsEndHTML = "";
|
||||
|
||||
var commentHeader = "";
|
||||
var commentFooter = "";
|
||||
var commentAvatar = "";
|
||||
var commentBody = "";
|
||||
|
||||
if ( comment.depth == 0 ) {
|
||||
depthClass += "root ";
|
||||
} else {
|
||||
depthClass="child flat-node"
|
||||
depthClass += "child "
|
||||
}
|
||||
if (comment.user.twitter_username && comment.user.twitter_username.length > 0) {
|
||||
twitterIcon = '<a href="http://twitter.com/'+comment.user.twitter_username+'" rel="noopener noreferrer" target="_blank"><%= image_tag("twitter-logo.svg", class:"icon-img", alt: "twitter logo") %></a>'
|
||||
}
|
||||
if (comment.user.github_username && comment.user.github_username.length > 0) {
|
||||
githubIcon = '<a href="http://github.com/'+comment.user.github_username+'" rel="noopener noreferrer" target="_blank"><%= image_tag("github-logo.svg", class:"icon-img", alt: "github logo") %></a>'
|
||||
|
||||
if ( comment.depth > 3 ) {
|
||||
depthClass += "comment--too-deep ";
|
||||
}
|
||||
|
||||
if (comment.newly_created) {
|
||||
customClass = "comment-created-via-fetch"
|
||||
}
|
||||
|
||||
if (comment.depth < 3) {
|
||||
detailsStartHTML = '<details open><summary><span> </span></summary>'
|
||||
detailsFinishHTML = '</details>'
|
||||
detailsStartHTML = `
|
||||
<details class="comment-wrapper comment-wrapper--deep-${ comment.depth } js-comment-wrapper" open>
|
||||
<summary aria-label="Toggle this comment (and replies)">
|
||||
<span class="inline-block align-middle ${ comment.depth > 0 ? 'mx-0' : 'm:mx-1'}">
|
||||
${ iconCollaspe }
|
||||
${ iconExpand }
|
||||
</span>
|
||||
<span class="js-collapse-comment-content inline-block align-middle"></span>
|
||||
</summary>
|
||||
`;
|
||||
detailsEndHTML = `</details>`;
|
||||
}
|
||||
|
||||
body = '<style>'+comment.css+'</style>\
|
||||
'+detailsStartHTML+'\
|
||||
<div class="comment-hash-marker" id="'+comment.id_code+'"></div>\
|
||||
<div id="comment-node-'+comment.id+'" class="single-comment-node '+depthClass+' comment-deep-'+comment.depth+'" "\
|
||||
data-comment-id="'+comment.id+'" data-comment-author-id="'+comment.user.id+'" data-current-user-comment="'+comment.newly_created+'" data-content-user-id="'+comment.user.id+'">\
|
||||
<div class="inner-comment '+customClass+'">\
|
||||
<div class="details">\
|
||||
<a href="/'+comment.user.username+'">\
|
||||
<img class="profile-pic" src="'+comment.user.profile_pic+'" alt="'+comment.user.username+'">\
|
||||
<span class="comment-username"><span class="comment-username-inner">'+comment.user.name+'</span></span>\
|
||||
</a>\
|
||||
'+twitterIcon+'\
|
||||
'+githubIcon+'\
|
||||
<div class="comment-date">\
|
||||
<a href="'+comment.url+'">\
|
||||
<time datetime="'+comment.published_timestamp+'">\
|
||||
'+comment.readable_publish_date+'\
|
||||
</time>\
|
||||
</a>\
|
||||
</div>\
|
||||
<button class="dropbtn">\
|
||||
<%= image_tag("overflow-horizontal.svg", class: "dropdown-icon", alt: "Toggle dropdown menu") %>\
|
||||
</button>\
|
||||
<div class="dropdown">\
|
||||
<div class="crayons-dropdown p-1 z-30 right-1 left-1 s:right-0 s:left-auto fs-base">\
|
||||
<a href="'+comment.url+'" class="crayons-link crayons-link--block">\
|
||||
Permalink\
|
||||
</a>\
|
||||
<a href="'+comment.url+'" class="crayons-link crayons-link--block permalink-copybtn" data-no-instant>\
|
||||
Copy Permalink\
|
||||
</a>\
|
||||
<a href="'+comment.url+'/settings" class="crayons-link crayons-link--block">\
|
||||
Settings\
|
||||
</a>\
|
||||
<a href="/report-abuse?url='+comment.url+'" class="crayons-link crayons-link--block">Report Abuse</a>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="body">\
|
||||
'+comment.body_html+'\
|
||||
'+reactions(comment)+'\
|
||||
</div>\
|
||||
'+actions(comment)+'\
|
||||
</div>\
|
||||
</div>\
|
||||
'+detailsFinishHTML;
|
||||
commentAvatar = `<a href="/${ comment.user.username }" class="shrink-0 crayons-avatar ${ comment.depth == 0 ? 'm:crayons-avatar--l mt-4 m:mt-3' : 'mt-4' }">
|
||||
<img class="crayons-avatar__image" width="32" height="32" src="${ comment.user.profile_pic }" alt="${ comment.user.username } profile" />
|
||||
</a>`;
|
||||
|
||||
return body;
|
||||
commentHeader = `<header class="comment__header">
|
||||
<a href="/${ comment.user.username }" class="crayons-link crayons-link--secondary flex items-center fw-medium">
|
||||
<span class="js-comment-username">${ comment.user.name }</span>
|
||||
</a>
|
||||
|
||||
<span class="color-base-30 px-2" role="presentation">•</span>
|
||||
|
||||
<a href="${ comment.url }" class="comment-date crayons-link crayons-link--secondary fs-s">
|
||||
<time datetime="${ comment.published_timestamp }">
|
||||
${ comment.readable_publish_date }
|
||||
</time>
|
||||
</a>
|
||||
|
||||
<div class="comment__dropdown">
|
||||
<button class="dropbtn comment__dropdown-trigger crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon" aria-label="Toggle dropdown menu" aria-haspopup="true">
|
||||
${ iconSmallOverflowHorizontal }
|
||||
</button>
|
||||
<ul class="crayons-dropdown p-1 right-1 s:right-0 s:left-auto fs-base dropdown">
|
||||
<li><a href="${ comment.url }" class="crayons-link crayons-link--block permalink-copybtn" aria-label="Copy link to ${ comment.user.name }'s comment" data-no-instant>Copy link</a></li>
|
||||
<li><a href="${ comment.url }/settings" class="crayons-link crayons-link--block" aria-label="Go to ${ comment.user.name }'s comment settings">Settings</a></li>
|
||||
<li><a href="/report-abuse?url=${ comment.url }" class="crayons-link crayons-link--block" aria-label="Report ${ comment.user.name }'s comment as abusive or violating our code of conduct and/or terms and conditions">Report abuse</a></li>
|
||||
<li class="${ comment.newly_created ? '' : 'hidden' }"><a href="${ comment.url }/edit" class="crayons-link crayons-link--block" rel="nofollow" aria-label="Delete this comment">Edit</a></li>
|
||||
<li class="${ comment.newly_created ? '' : 'hidden' }"><a data-no-instant="" href="${ comment.url }/delete_confirm" class="crayons-link crayons-link--block" rel="nofollow" aria-label="Delete this comment">Delete</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>`;
|
||||
|
||||
commentFooter = `<footer class="comment__footer">
|
||||
${ react(comment) }
|
||||
${ reply(comment) }
|
||||
</footer>`;
|
||||
|
||||
commentBody = `${ detailsStartHTML }
|
||||
<div class="comment single-comment-node ${ depthClass } comment--deep-${ comment.depth }" id="comment-node-${ comment.id }" data-comment-id="${ comment.id }" data-path="${ comment.url }" data-comment-author-id="${ comment.user.id }" data-current-user-comment="${ comment.newly_created }" data-content-user-id="${ comment.user.id }">
|
||||
<div class="comment__inner">
|
||||
${ commentAvatar }
|
||||
<div class="inner-comment comment__details">
|
||||
<div class="comment__content crayons-card">
|
||||
${ commentHeader }
|
||||
<div class="comment__body text-styles text-styles--secondary body">
|
||||
${ comment.body_html }
|
||||
</div>
|
||||
</div>
|
||||
${ commentFooter }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
${ detailsEndHTML }`;
|
||||
|
||||
return commentBody;
|
||||
}
|
||||
|
||||
function actions(comment) {
|
||||
function reply(comment) {
|
||||
var iconSmallComment = `<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" class="crayons-icon reaction-icon not-reacted"><path d="M10.5 5h3a6 6 0 110 12v2.625c-3.75-1.5-9-3.75-9-8.625a6 6 0 016-6zM12 15.5h1.5a4.501 4.501 0 001.722-8.657A4.5 4.5 0 0013.5 6.5h-3A4.5 4.5 0 006 11c0 2.707 1.846 4.475 6 6.36V15.5z"/></svg>`;
|
||||
var replyButton = `<a class="js actions crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon-left toggle-reply-form mr-1 inline-flex"
|
||||
href="#${ comment.url }"
|
||||
data-comment-id="${ comment.id }"
|
||||
data-path="${ comment.url }"
|
||||
rel="nofollow">
|
||||
${ iconSmallComment }
|
||||
<span class="hidden m:inline-block">Reply</span>
|
||||
</a>`;
|
||||
if (comment.newly_created) {
|
||||
return '<div class="actions" data-comment-id="'+comment.id+'" data-path="'+comment.url+'">\
|
||||
<span class="current-user-actions" style="display: '+ (comment.newly_created ? 'inline-block' : 'none') +';">\
|
||||
<a data-no-instant="" href="'+comment.url+'/delete_confirm" class="edit-butt" rel="nofollow">DELETE</a>\
|
||||
<a href="'+comment.url+'/edit" class="edit-butt" rel="nofollow">EDIT</a>\
|
||||
</span>\
|
||||
<a href="#" class="toggle-reply-form" rel="nofollow">Reply</a>\
|
||||
</div>';
|
||||
} else {
|
||||
return '<div class="actions" data-comment-id="'+comment.id+'" data-path="'+comment.url+'" data-commentable-id="'+comment.commentable.id+'">\
|
||||
<a href="'+comment.url+'" rel="nofollow">VIEW/REPLY</a>\
|
||||
</div>';
|
||||
return replyButton;
|
||||
}
|
||||
}
|
||||
|
||||
function reactions(comment) {
|
||||
if (comment.newly_created) {
|
||||
return '<button class="reaction-button reacted" id="button-for-comment-'+comment.id+'" data-comment-id="'+comment.id+'">\
|
||||
<img src="<%= asset_path("favorite-heart-outline-button.svg") %>" alt="Favorite heart outline button">\
|
||||
<img class="voted-heart" src="<%= asset_path("emoji/emoji-one-heart.png") %>" alt="Favorite heart button">\
|
||||
<span class="reactions-count" id="reactions-count-'+comment.id+'">1</span></button>';
|
||||
} else {
|
||||
if (comment.heart_ids.indexOf(userData().id) > -1) {
|
||||
var reactedClass = "reacted";
|
||||
} else {
|
||||
var reactedClass = ""
|
||||
}
|
||||
return '<button style="background:white" class="reaction-button '+ reactedClass +'" id="button-for-comment-'+comment.id+'" data-comment-id="'+comment.id+'">\
|
||||
<img src="<%= asset_path("favorite-heart-outline-button.svg") %>" alt="Favorite heart outline button">\
|
||||
<img class="voted-heart" src="<%= asset_path("emoji/emoji-one-heart.png") %>" alt="Favorite heart button">\
|
||||
<span class="reactions-count" id="reactions-count-'+comment.id+'">'+comment.public_reactions_count+'</span></button>';
|
||||
function react(comment) {
|
||||
var reactedClass = "";
|
||||
var num = 1;
|
||||
var iconSmallHeart = `<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" class="crayons-icon reaction-icon not-reacted"><path d="M18.884 12.595l.01.011L12 19.5l-6.894-6.894.01-.01A4.875 4.875 0 0112 5.73a4.875 4.875 0 016.884 6.865zM6.431 7.037a3.375 3.375 0 000 4.773L12 17.38l5.569-5.569a3.375 3.375 0 10-4.773-4.773L9.613 10.22l-1.06-1.062 2.371-2.372a3.375 3.375 0 00-4.492.25v.001z"/></svg>`;
|
||||
var iconSmallHeartFilled = `<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class="crayons-icon reaction-icon--like reaction-icon reacted"><path d="M5.116 12.595a4.875 4.875 0 015.56-7.68h-.002L7.493 8.098l1.06 1.061 3.181-3.182a4.875 4.875 0 016.895 6.894L12 19.5l-6.894-6.894.01-.01z"/></svg>`;
|
||||
|
||||
if (!comment.newly_created && comment.heart_ids.indexOf(userData().id) > -1) {
|
||||
reactedClass = "reacted"
|
||||
}
|
||||
|
||||
if (!comment.newly_created) {
|
||||
num = comment.public_reactions_count;
|
||||
}
|
||||
|
||||
var reactButton = `<button class="crayons-btn crayons-btn--ghost crayons-btn--icon-left crayons-btn--s mr-1 reaction-like inline-flex reaction-button" id="button-for-comment-${ comment.id }" data-comment-id="${ comment.id }">
|
||||
${ iconSmallHeart }
|
||||
${ iconSmallHeartFilled }
|
||||
<span class="reactions-count" id="reactions-count-${ comment.id }">${ num }</span>
|
||||
<span class="reactions-label hidden m:inline-block">like</span>
|
||||
</button>`;
|
||||
|
||||
return reactButton;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,775 +0,0 @@
|
|||
@import 'variables';
|
||||
@import 'mixins';
|
||||
@import 'functions';
|
||||
@import 'config/import';
|
||||
|
||||
%kbd {
|
||||
display: inline-block;
|
||||
padding: 3px 5px;
|
||||
font-size: 11px;
|
||||
line-height: 10px;
|
||||
color: #444d56;
|
||||
vertical-align: middle;
|
||||
background-color: #fafbfc;
|
||||
border: solid 1px #c6cbd1;
|
||||
border-bottom-color: #959da5;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 -1px 0 #959da5;
|
||||
}
|
||||
|
||||
$indent-distance: calc(1.1vw + 13px);
|
||||
|
||||
@keyframes fade-out {
|
||||
0% {
|
||||
background-color: rgb(208, 255, 235);
|
||||
}
|
||||
100% {
|
||||
background-color: white;
|
||||
}
|
||||
}
|
||||
|
||||
a.header-link {
|
||||
color: var(--body-color);
|
||||
display: block;
|
||||
&:hover {
|
||||
color: var(--body-color);
|
||||
}
|
||||
}
|
||||
|
||||
.comments {
|
||||
.picture {
|
||||
height: 180px;
|
||||
max-width: 900px;
|
||||
margin: auto;
|
||||
border-top-right-radius: 5px;
|
||||
border-top-left-radius: 5px;
|
||||
@media screen and (min-width: 390px) {
|
||||
height: 240px;
|
||||
}
|
||||
@media screen and (min-width: 820px) {
|
||||
height: 280px;
|
||||
}
|
||||
background-color: #ecf0f2;
|
||||
background: #ecf0f2 no-repeat top center;
|
||||
background-size: cover;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.blank-comment-space {
|
||||
height: 3px;
|
||||
@media screen and (min-width: 820px) {
|
||||
height: 0px;
|
||||
}
|
||||
}
|
||||
.article-header {
|
||||
width: 820px;
|
||||
max-width: 100%;
|
||||
margin: 50px auto 10px;
|
||||
padding: 0px 0px 90px;
|
||||
background: var(--card-bg);
|
||||
z-index: 3;
|
||||
position: relative;
|
||||
@media screen and (min-width: 820px) {
|
||||
margin: 72px auto 10px;
|
||||
border-radius: 5px;
|
||||
@include themeable(
|
||||
border,
|
||||
theme-container-border,
|
||||
1px solid darken($lightest-gray, 4%)
|
||||
);
|
||||
}
|
||||
h3 {
|
||||
width: 94%;
|
||||
margin: 12px 0 5px;
|
||||
margin-left: 1.8%;
|
||||
font-weight: 500;
|
||||
font-size: calc(1.5vw + 22px);
|
||||
}
|
||||
h4 {
|
||||
margin: 0;
|
||||
font-weight: 300;
|
||||
color: rgb(195, 195, 195);
|
||||
font-size: 17px;
|
||||
width: 96%;
|
||||
margin: auto;
|
||||
margin-bottom: -40px;
|
||||
a {
|
||||
color: rgb(105, 103, 103);
|
||||
}
|
||||
}
|
||||
.body {
|
||||
padding: 60px 0px 0px;
|
||||
width: 96%;
|
||||
margin: auto;
|
||||
margin-bottom: -35px;
|
||||
.read-more {
|
||||
color: var(--link-brand-color);
|
||||
display: inline-block;
|
||||
&:hover {
|
||||
opacity: 0.96;
|
||||
}
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 350px;
|
||||
}
|
||||
kbd {
|
||||
@extend %kbd;
|
||||
}
|
||||
}
|
||||
}
|
||||
.single-comment-header {
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.comments-container {
|
||||
padding-top: 10px;
|
||||
margin: auto;
|
||||
margin-bottom: var(--su-4);
|
||||
text-align: left;
|
||||
overflow-wrap: break-word;
|
||||
&.comments-dedicated-page-container {
|
||||
width: 800px;
|
||||
max-width: 96%;
|
||||
min-height: calc(97vh - 200px);
|
||||
}
|
||||
|
||||
img.icon-image {
|
||||
height: 21px;
|
||||
opacity: 0.7;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.top-level-actions {
|
||||
margin: 0px 0px 85px;
|
||||
padding: 3px 0px;
|
||||
z-index: 4;
|
||||
position: relative;
|
||||
border-radius: 3px;
|
||||
font-size: calc(0.35vw + 16px);
|
||||
h3 {
|
||||
margin: 5px 0px;
|
||||
a {
|
||||
font-size: 0.62em;
|
||||
background: $black;
|
||||
color: white;
|
||||
margin: 2px 0px 2px;
|
||||
margin-right: 5px;
|
||||
vertical-align: 2px;
|
||||
}
|
||||
}
|
||||
.comment-action-buttons,
|
||||
.comment-action-text {
|
||||
display: inline-block;
|
||||
color: $medium-gray;
|
||||
font-weight: 300;
|
||||
}
|
||||
a {
|
||||
display: inline-block;
|
||||
background: $purple;
|
||||
border-radius: 3px;
|
||||
color: $black;
|
||||
font-family: $helvetica-condensed;
|
||||
font-stretch: condensed;
|
||||
padding: 4px 8px;
|
||||
font-size: 0.77em;
|
||||
vertical-align: 1px;
|
||||
margin: 8px 0px 2px;
|
||||
}
|
||||
.commentable-title {
|
||||
font-size: calc(0.3vw + 16px);
|
||||
color: $medium-gray;
|
||||
}
|
||||
}
|
||||
|
||||
details {
|
||||
details {
|
||||
.comment-deep-1,
|
||||
.comment-deep-2 {
|
||||
margin-top: -123px;
|
||||
}
|
||||
// this ms-lang hack (which behaves like a media query) is going to be ignored by all browsers
|
||||
// except IE and 11 and it fixes indentation on the unsupported <details> tags
|
||||
_:-ms-lang(x),
|
||||
.comment-deep-1,
|
||||
.comment-deep-2 {
|
||||
margin-top: 0px;
|
||||
}
|
||||
summary {
|
||||
position: relative;
|
||||
}
|
||||
&[open] {
|
||||
> summary {
|
||||
width: calc(1.1vw + 12px); //slightly smaller than indent distance
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
summary {
|
||||
cursor: pointer;
|
||||
color: lighten($medium-gray, 8%);
|
||||
font-size: 14.5px;
|
||||
font-style: oblique;
|
||||
padding: 4px 0px;
|
||||
padding-left: 4px;
|
||||
user-select: none;
|
||||
&:active {
|
||||
outline: 0;
|
||||
box-shadow: 0px 0px 0px $light-medium-gray !important;
|
||||
}
|
||||
&:focus-visible {
|
||||
outline: 0;
|
||||
&:not(:active) {
|
||||
box-shadow: 0px 0px 6px $light-medium-gray !important;
|
||||
}
|
||||
}
|
||||
span {
|
||||
display: inline-block;
|
||||
width: calc(100% - 50px);
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.comment-trees {
|
||||
.comment-hash-marker {
|
||||
margin-top: -45px;
|
||||
margin-bottom: 45px;
|
||||
border: 1px solid transparent;
|
||||
z-index: var(--z-negative);
|
||||
position: relative;
|
||||
&:target + .single-comment-node {
|
||||
animation-name: fade-out;
|
||||
animation-duration: 5s;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
}
|
||||
.root-comment {
|
||||
margin-top: -80px;
|
||||
.comment-parent-link {
|
||||
background: var(--card-bg);
|
||||
@include themeable(
|
||||
border,
|
||||
theme-container-border,
|
||||
1px solid $medium-gray
|
||||
);
|
||||
display: block;
|
||||
padding: 9px 12px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 0.8em;
|
||||
@include themeable(
|
||||
background,
|
||||
theme-container-accent-background,
|
||||
lighten($lightest-gray, 1%)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
.comment-view-parent {
|
||||
margin-bottom: 7px;
|
||||
text-align: left;
|
||||
font-family: $helvetica-condensed;
|
||||
font-size: 0.8em;
|
||||
background: $purple;
|
||||
display: inline-block;
|
||||
padding: 2px 4px;
|
||||
border-radius: 3px;
|
||||
margin-right: 5px;
|
||||
vertical-align: top;
|
||||
&.comment-view-commentable {
|
||||
background: transparent;
|
||||
max-width: calc(100% - 100px);
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background: $red;
|
||||
max-width: 730px;
|
||||
font-family: var(--ff-sans-serif);
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.single-comment-node {
|
||||
padding: 2px 0px 0px $indent-distance;
|
||||
text-align: left;
|
||||
&.root {
|
||||
padding: 0px 0px 2px 0;
|
||||
}
|
||||
margin-top: 15px;
|
||||
font-size: 17px;
|
||||
position: relative;
|
||||
@media screen and (min-width: 390px) {
|
||||
font-size: 20px;
|
||||
}
|
||||
&.flat-node {
|
||||
padding: 0px;
|
||||
margin-top: -3px;
|
||||
margin-bottom: -3px;
|
||||
&.root {
|
||||
padding: 2px 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.inner-comment {
|
||||
border-top-left-radius: 0px;
|
||||
border-top-right-radius: 0px;
|
||||
}
|
||||
button {
|
||||
margin-bottom: 3px;
|
||||
z-index: 7;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
.comment-deep-3 {
|
||||
margin-top: -5px;
|
||||
padding: 2px 0px 2px calc(0.9vw + 7px);
|
||||
button {
|
||||
margin-bottom: 3px;
|
||||
z-index: 8;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
.permalink {
|
||||
width: 40px;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
margin-top: calc(0.4vw + 12px);
|
||||
text-align: center;
|
||||
opacity: 0.9;
|
||||
img {
|
||||
width: 14px;
|
||||
}
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.low-quality-comment-marker {
|
||||
font-size: 0.66em;
|
||||
padding: 6px 13px;
|
||||
@include themeable(
|
||||
background,
|
||||
theme-container-accent-background,
|
||||
$light-gray
|
||||
);
|
||||
font-weight: bold;
|
||||
border-bottom: 1px solid $light-medium-gray;
|
||||
a {
|
||||
background: lighten($green, 14%);
|
||||
color: $black;
|
||||
padding: 1px 5px 3px;
|
||||
border-radius: 3px;
|
||||
vertical-align: -1px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
img {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
border-radius: 100px;
|
||||
border: 2px solid $medium-gray;
|
||||
vertical-align: -0.6em;
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
.low-quality-comment > *:not(.dropdown) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.body {
|
||||
padding: 1px;
|
||||
padding-left: 1.5%;
|
||||
padding-right: 1.5%;
|
||||
padding-bottom: 5px;
|
||||
margin: 0;
|
||||
width: 96%;
|
||||
font-size: 0.95em;
|
||||
line-height: 1.35em;
|
||||
overflow: hidden;
|
||||
margin-bottom: -28px;
|
||||
word-wrap: break-word;
|
||||
font-family: var(--ff-sans-serif);
|
||||
position: relative;
|
||||
margin-left: 1px;
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
padding: 0px;
|
||||
margin: 4px 0px calc(1.1vw + 10px);
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
p {
|
||||
padding: 0px;
|
||||
margin: 4px 0px calc(1.1vw + 10px);
|
||||
}
|
||||
ul,
|
||||
ol {
|
||||
padding-left: 6px;
|
||||
margin: 0.8em 0.7em 0.8em 1em;
|
||||
}
|
||||
ul {
|
||||
list-style-type: square;
|
||||
}
|
||||
li {
|
||||
margin: 3px 0px calc(0.5vw + 5px);
|
||||
}
|
||||
blockquote {
|
||||
border-left: calc(0.2vw + 2px) solid $dark-gray;
|
||||
padding: 0.1% 3% 0.1% 2%;
|
||||
margin: 1.6em 1vw;
|
||||
font-size: 0.92em;
|
||||
line-height: 1.4em;
|
||||
p {
|
||||
padding: 0;
|
||||
margin: 0.95em 0 0.95em;
|
||||
}
|
||||
&.twitter-tweet {
|
||||
background: white;
|
||||
max-width: 480px;
|
||||
min-height: 135px;
|
||||
border: 1px solid #e9eef2;
|
||||
font-size: 17px;
|
||||
line-height: 20px;
|
||||
border-radius: 5px;
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
.edited-notification {
|
||||
color: lighten($medium-gray, 20%);
|
||||
font-size: 0.7em;
|
||||
padding: 3px 0px 0px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: calc(50vh + 100px);
|
||||
}
|
||||
.table-wrapper-paragraph {
|
||||
width: 100%;
|
||||
margin-left: 0%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
a {
|
||||
&.anchor {
|
||||
padding-top: 50px;
|
||||
margin-top: -50px;
|
||||
-webkit-background-clip: content-box;
|
||||
background-clip: content-box;
|
||||
}
|
||||
}
|
||||
kbd {
|
||||
@extend %kbd;
|
||||
}
|
||||
.liquid-comment {
|
||||
.details {
|
||||
.comment-date {
|
||||
top: calc(14px - 0.25vw);
|
||||
}
|
||||
}
|
||||
}
|
||||
&.hidden-comment {
|
||||
padding: 5px 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.icon-img {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin-right: 0px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.details {
|
||||
padding: 0px;
|
||||
border-top-left-radius: 3px;
|
||||
color: var(--link-brand-color);
|
||||
position: relative;
|
||||
.comment-date {
|
||||
border: none;
|
||||
position: absolute;
|
||||
top: calc(14px - 0.25vw);
|
||||
right: calc(35px + 0.2vw);
|
||||
font-size: 12px;
|
||||
text-align: right;
|
||||
a {
|
||||
color: var(--card-color-tertiary);
|
||||
}
|
||||
}
|
||||
.dropbtn {
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: calc(0.3vw + 13px);
|
||||
right: 10px;
|
||||
&.commentable-hidden {
|
||||
top: calc(0.3vw + 8px);
|
||||
}
|
||||
svg {
|
||||
transform: translateY(3px);
|
||||
fill: var(--card-color-tertiary);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
right: 200px;
|
||||
display: inline-block;
|
||||
|
||||
@media screen and (min-width: 580px) {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.dropdown-icon {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 7px;
|
||||
padding: 4px;
|
||||
max-width: 15px;
|
||||
max-height: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&.hidden-comment {
|
||||
.dropbtn {
|
||||
top: calc(0.3vw + 8px);
|
||||
}
|
||||
}
|
||||
|
||||
img.profile-pic {
|
||||
height: 33px;
|
||||
width: 33px;
|
||||
border-radius: 50px;
|
||||
margin: 1.5% 0.2% 1.5% 1.5%;
|
||||
}
|
||||
.comment-username {
|
||||
vertical-align: calc(0.62vw + 13px);
|
||||
}
|
||||
.comment-username-inner {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: calc(60% - 20px);
|
||||
}
|
||||
.icon-img {
|
||||
vertical-align: calc(0.7vw + 9px);
|
||||
margin-left: 2px;
|
||||
}
|
||||
.op-marker {
|
||||
display: none;
|
||||
@media screen and (min-width: 580px) {
|
||||
display: inline-block;
|
||||
vertical-align: calc(0.7vw + 12px);
|
||||
background: $purple;
|
||||
color: $black;
|
||||
padding: 2px 6px 2px;
|
||||
margin-left: 0.3vw;
|
||||
font-family: $helvetica-condensed;
|
||||
font-stretch: condensed;
|
||||
font-size: 0.78em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
a {
|
||||
@include themeable(color, theme-secondary-color, lighten($dark-gray, 3%));
|
||||
}
|
||||
}
|
||||
.reaction-button,
|
||||
.dropbtn {
|
||||
border: 0px;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
height: 32px;
|
||||
display: block;
|
||||
padding: 0px;
|
||||
margin-left: 2px;
|
||||
position: relative;
|
||||
margin-top: calc(-0.6vw - 4px);
|
||||
z-index: 8;
|
||||
position: relative;
|
||||
&.reaction-button {
|
||||
padding-right: 25px;
|
||||
padding-top: 4px;
|
||||
margin-top: 0px;
|
||||
height: 25px;
|
||||
}
|
||||
.reactions-count {
|
||||
font-size: 0.7em;
|
||||
background: $light-gray;
|
||||
padding: 1px 5px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid darken($light-gray, 10%);
|
||||
margin-left: 1px;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 24px;
|
||||
}
|
||||
img {
|
||||
height: 21px;
|
||||
width: 21px;
|
||||
opacity: 0.62;
|
||||
left: 0px;
|
||||
&.dropdown-icon {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
img {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.voted-heart {
|
||||
display: none;
|
||||
vertical-align: 0px;
|
||||
margin-left: 0px;
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
opacity: 0.9;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 390px) {
|
||||
vertical-align: -7px;
|
||||
}
|
||||
&.reacted {
|
||||
color: $green;
|
||||
img {
|
||||
display: none;
|
||||
}
|
||||
.voted-heart {
|
||||
display: inline-block;
|
||||
}
|
||||
.reactions-count {
|
||||
color: $black;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
img.icon-image {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
font-size: 0.8em;
|
||||
padding: 0.3em 0.6em 0.3em 0.4em;
|
||||
text-align: right;
|
||||
position: relative;
|
||||
min-height: 1.2em;
|
||||
z-index: 5;
|
||||
text-transform: capitalize;
|
||||
margin-left: 58px;
|
||||
a.thread-indication {
|
||||
color: lighten($medium-gray, 22%);
|
||||
font-size: 0.8em;
|
||||
cursor: default;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
a.register-now-cta {
|
||||
font-size: 1.4em;
|
||||
background: lighten($yellow, 12%);
|
||||
border: 1px solid darken($yellow, 15%);
|
||||
box-shadow: 5px 6px 0px darken($yellow, 15%);
|
||||
color: $black;
|
||||
padding: 5px 10px;
|
||||
margin-right: 8px;
|
||||
vertical-align: 20px;
|
||||
line-height: 1.8em;
|
||||
}
|
||||
.current-user-actions {
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
a {
|
||||
margin-right: 10px;
|
||||
display: inline-block;
|
||||
color: $medium-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
.inner-comment {
|
||||
padding: 0px;
|
||||
border: 1px solid $light-medium-gray;
|
||||
background: var(--card-bg);
|
||||
&.comment-created-via-fetch {
|
||||
animation: comment-create 1.2s;
|
||||
.body {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
.comment-read-more {
|
||||
background: $green !important;
|
||||
padding: 3px 6px;
|
||||
display: block;
|
||||
width: 250px;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
border-radius: 3px;
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
background: lighten($green, 5%) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
0% {
|
||||
opacity: 0.5;
|
||||
height: 21px;
|
||||
width: 18px;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
height: 25px;
|
||||
width: 22px;
|
||||
}
|
||||
}
|
||||
@keyframes comment-create {
|
||||
from {
|
||||
background-color: $light-green;
|
||||
}
|
||||
to {
|
||||
@include themeable(background-color, theme-container-background, #fff);
|
||||
}
|
||||
}
|
||||
|
||||
#response-templates-data {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.comments-settings__row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
grid-gap: var(--su-2);
|
||||
|
||||
&--subtitle {
|
||||
color: var(--base-60);
|
||||
}
|
||||
}
|
||||
|
|
@ -615,6 +615,7 @@
|
|||
(),
|
||||
false
|
||||
),
|
||||
('fs', 'font-style', ('italic': italic, 'normal': normal), (), false),
|
||||
(
|
||||
'text',
|
||||
'text-transform',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
@import 'variables';
|
||||
|
||||
#error_explanation {
|
||||
width: 100%;
|
||||
border: 2px solid #d94949;
|
||||
|
|
@ -24,39 +22,3 @@
|
|||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove post confirmation
|
||||
.delete-confirm.container {
|
||||
padding: 150px 10px;
|
||||
min-height: 300px;
|
||||
text-align: center;
|
||||
h4 {
|
||||
background: $black;
|
||||
padding: 5px 8px;
|
||||
color: $white;
|
||||
display: inline-block;
|
||||
margin-bottom: 0px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 22px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
a.delete-link {
|
||||
background: $red;
|
||||
color: white;
|
||||
padding: 10px 15px;
|
||||
&:hover {
|
||||
color: white;
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
form button {
|
||||
background: $red;
|
||||
color: white;
|
||||
font-size: 1.5em;
|
||||
border: 0px;
|
||||
border-radius: 3px;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
@import 'podcast-episodes-show';
|
||||
@import 'podcast-form';
|
||||
@import 'user-profile-header';
|
||||
@import 'comments';
|
||||
@import 'live';
|
||||
@import 'preact/sidebar-widget';
|
||||
@import 'preact/article-form';
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@
|
|||
}
|
||||
|
||||
.podcast-episode-container {
|
||||
font-family: var(--ff-sans-serif);
|
||||
|
||||
.hero {
|
||||
padding-bottom: 30px;
|
||||
text-align: center;
|
||||
|
|
@ -204,13 +202,6 @@
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
.body {
|
||||
padding: calc(0.7vw + 4px) 0px calc(0.5vw + 2px);
|
||||
font-family: var(--ff-sans-serif);
|
||||
img {
|
||||
min-height: 0px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
@import '../config/import';
|
||||
|
||||
.comment-form {
|
||||
--preview-display: none;
|
||||
--field-display: flex;
|
||||
|
||||
display: flex;
|
||||
margin-bottom: var(--su-4);
|
||||
|
||||
&__field {
|
||||
display: flex;
|
||||
display: var(--field-display);
|
||||
flex: 1 auto;
|
||||
flex-direction: column;
|
||||
margin-bottom: var(--su-3);
|
||||
|
|
@ -63,34 +67,192 @@
|
|||
border: 1px solid var(--base-20);
|
||||
margin-bottom: var(--su-3);
|
||||
background: var(--card-bg);
|
||||
}
|
||||
}
|
||||
|
||||
// temporary until we have new design for comments
|
||||
.inner-comment {
|
||||
&.replying {
|
||||
.actions,
|
||||
.reaction-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-form {
|
||||
margin: var(--su-6) var(--su-4) 0 var(--su-4);
|
||||
}
|
||||
}
|
||||
|
||||
.comment-form {
|
||||
.comment-form__preview {
|
||||
display: none;
|
||||
display: var(--preview-display);
|
||||
}
|
||||
|
||||
&.preview-open {
|
||||
.comment-form__preview {
|
||||
--preview-display: block;
|
||||
--field-display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-wrapper {
|
||||
--level-n-indent: var(--su-3);
|
||||
--level-1-indent: var(--su-4);
|
||||
|
||||
@media (min-width: $breakpoint-m) {
|
||||
--level-n-indent: calc(var(--su-4) + var(--su-1));
|
||||
--level-1-indent: calc(var(--su-6) + var(--su-1));
|
||||
}
|
||||
position: relative;
|
||||
|
||||
> summary {
|
||||
position: static;
|
||||
display: block;
|
||||
align-items: center;
|
||||
transform: initial;
|
||||
top: 0;
|
||||
left: var(--indent);
|
||||
cursor: pointer;
|
||||
font-size: var(--fs-s);
|
||||
color: var(--base-60);
|
||||
margin-bottom: var(--su-4);
|
||||
margin-left: var(--indent);
|
||||
padding: var(--su-1) var(--su-2);
|
||||
font-style: italic;
|
||||
border-radius: var(--radius);
|
||||
background: var(--base-0);
|
||||
|
||||
.expanded {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
display: block;
|
||||
}
|
||||
.comment-form__field {
|
||||
|
||||
&::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&--deep-0 > summary {
|
||||
--indent: 0;
|
||||
}
|
||||
|
||||
&--deep-1:not(.root) > summary {
|
||||
--indent: var(--level-1-indent);
|
||||
}
|
||||
|
||||
&--deep-2:not(.root) > summary {
|
||||
--indent: var(--level-n-indent);
|
||||
}
|
||||
|
||||
&[open] > summary {
|
||||
position: absolute;
|
||||
top: var(--su-8);
|
||||
background: transparent;
|
||||
width: auto;
|
||||
padding: var(--su-1) 0;
|
||||
margin-left: 0;
|
||||
|
||||
@media (min-width: $breakpoint-s) {
|
||||
// display: none;
|
||||
}
|
||||
|
||||
.expanded {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.expanded,
|
||||
.collapsed {
|
||||
opacity: 0.5;
|
||||
transition: all var(--transition-props);
|
||||
}
|
||||
}
|
||||
|
||||
&[open]:hover {
|
||||
> summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.expanded,
|
||||
.collapsed {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.comment {
|
||||
--comment-gap: var(--su-4);
|
||||
--dropdown-opacity: 0.5;
|
||||
--footer-display: flex;
|
||||
|
||||
@media (min-width: $breakpoint-m) {
|
||||
--comment-gap: var(--su-6);
|
||||
}
|
||||
|
||||
&.child {
|
||||
&:not(.comment--too-deep) {
|
||||
padding-left: var(--level-n-indent);
|
||||
}
|
||||
&.comment--deep-1 {
|
||||
padding-left: var(--level-1-indent);
|
||||
}
|
||||
}
|
||||
|
||||
&__dropdown-trigger {
|
||||
@media (min-width: $breakpoint-s) {
|
||||
opacity: var(--dropdown-opacity);
|
||||
}
|
||||
}
|
||||
|
||||
&__dropdown {
|
||||
margin-left: auto;
|
||||
margin-right: calc(-1 * var(--su-3));
|
||||
position: relative;
|
||||
top: calc(-1 * var(--su-2));
|
||||
}
|
||||
|
||||
&__inner {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: var(--comment-gap);
|
||||
|
||||
&:hover,
|
||||
&:focus-within {
|
||||
--dropdown-opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&__details {
|
||||
padding-left: var(--su-2);
|
||||
flex: 1 auto;
|
||||
min-width: 0;
|
||||
|
||||
&.replying {
|
||||
--footer-display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
padding: var(--su-1);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--su-2) var(--su-3) 0;
|
||||
font-size: var(--fs-s);
|
||||
|
||||
@media (min-width: $breakpoint-m) {
|
||||
font-size: var(--fs-base);
|
||||
}
|
||||
}
|
||||
|
||||
&__body {
|
||||
padding: 0 var(--su-3);
|
||||
margin: var(--su-2) 0 var(--su-4);
|
||||
}
|
||||
|
||||
&__footer {
|
||||
// border-top: 1px solid var(--base-10);
|
||||
padding-top: var(--su-1);
|
||||
display: var(--footer-display);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__quality-marker {
|
||||
border-bottom: 1px solid var(--base-10);
|
||||
padding: var(--su-3);
|
||||
padding-top: var(--su-2);
|
||||
font-weight: var(--fw-medium);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<% if articles %>
|
||||
<section class="crayons-card crayons-card--secondary text-padding mb-4 print-hidden">
|
||||
<h2 class="crayons-title">Read next</h2>
|
||||
<h2 class="crayons-subtitle-1">Read next</h2>
|
||||
<% articles.each do |article| %>
|
||||
<a href="<%= article.path %>" data-preload-image="<%= cloud_cover_url(article.main_image) %>" class="crayons-link mt-6 block">
|
||||
<div class="flex items-center">
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
<a href="/code-of-conduct" class="crayons-link crayons-link--brand">Code of Conduct</a>
|
||||
<span class="opacity-25 px-2">•</span>
|
||||
<a href="/report-abuse" class="crayons-link crayons-link--brand">Report abuse</a>
|
||||
<nav class="fs-s align-center block" aria-label="Conduct controls">
|
||||
<a href="/code-of-conduct" class="crayons-link crayons-link--secondary">Code of Conduct</a>
|
||||
<span class="opacity-25 px-2" role="presentation">•</span>
|
||||
<a href="/report-abuse" class="crayons-link crayons-link--secondary">Report abuse</a>
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,22 @@
|
|||
<% cache("whole-comment-area-#{@article.id}-#{@article.last_comment_at}-#{@article.show_comments}", expires_in: 2.hours) do %>
|
||||
<section id="comments" data-updated-at="<%= Time.current %>" class="text-padding mb-4 border-t-1 border-0 border-solid border-base-10">
|
||||
<% if @article.show_comments %>
|
||||
<header class="relative flex justify-between items-center mb-4">
|
||||
<h3 class="crayons-title">Discussion</h3>
|
||||
<header class="relative flex justify-between items-center mb-6">
|
||||
<h3 class="crayons-subtitle-1">Discussion</h3>
|
||||
<div id="comment-subscription">
|
||||
<div role="presentation" class="crayons-btn-group">
|
||||
<span class="crayons-btn crayons-btn--outlined">Subscribe</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div
|
||||
class="comments-container"
|
||||
id="comments-container"
|
||||
data-commentable-id="<%= @article.id %>"
|
||||
data-commentable-type="Article">
|
||||
<%= render "/comments/form",
|
||||
commentable: @article,
|
||||
commentable_type: "Article" %>
|
||||
<div class="comment-trees" id="comment-trees-container">
|
||||
<%= render "/comments/form", commentable: @article, commentable_type: "Article" %>
|
||||
|
||||
<div class="comments" id="comment-trees-container">
|
||||
<% if @article.comments_count > 0 %>
|
||||
<% Comment.tree_for(@article, @comments_to_show_count).each do |comment, sub_comments| %>
|
||||
<% cache ["comment_root_cached_tree", comment] do %>
|
||||
|
|
@ -27,6 +26,7 @@
|
|||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "articles/comments_actions" %>
|
||||
<% end %>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,23 @@
|
|||
<div class="container delete-confirm">
|
||||
<h4><%= @article.title %></h4>
|
||||
<h1>Are you sure you want to delete this article?</h1>
|
||||
<div class="crayons-layout crayons-layout--limited-l gap-0">
|
||||
<div class="crayons-card crayons-card--secondary text-styles text-styles--secondary text-padding -mb-1 mx-3 m:mx-6 mt-3">
|
||||
<%= @article.title %>
|
||||
</div>
|
||||
<div class="crayons-card text-padding">
|
||||
<h1 class="crayons-subtitle-1 mb-2">Are you sure you want to delete this article?</h1>
|
||||
<p class="fs-l mb-4">
|
||||
You cannot undo this action, perhaps you just want to
|
||||
<a data-no-instant href="<%= @article.path %>/edit">
|
||||
<%= @article.published ? "unpublish" : "edit" %>
|
||||
</a>
|
||||
instead?
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
You cannot undo this action, perhaps you just want to
|
||||
<a data-no-instant href="<%= @article.path %>/edit">
|
||||
<%= @article.published ? "unpublish" : "edit" %>
|
||||
</a>
|
||||
instead?
|
||||
</h2>
|
||||
<%= form_tag "/articles/#{@article.id}", method: :delete do %>
|
||||
<button class="crayons-btn crayons-btn--danger">Delete</button>
|
||||
<% end %>
|
||||
<%= form_tag "/articles/#{@article.id}", method: :delete do %>
|
||||
<button class="crayons-btn crayons-btn--danger">Delete</button>
|
||||
<a data-no-instant href="<%= @article.path %>/edit" class="crayons-btn crayons-btn--secondary">
|
||||
<%= @article.published ? "Unpublish" : "Edit" %>
|
||||
</a>
|
||||
<a data-no-instant href="<%= @article.path %>" class="crayons-btn crayons-btn--ghost">Dismiss</a>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,35 @@
|
|||
<% if comment && comment.user %>
|
||||
<% if comment.depth < 3 && !should_be_hidden?(comment, @root_comment) %>
|
||||
<details open>
|
||||
<summary><span> </span></summary>
|
||||
<%= render("comments/comment_proper",
|
||||
comment: comment,
|
||||
commentable: commentable,
|
||||
is_view_root: is_view_root,
|
||||
is_childless: is_childless,
|
||||
subtree_html: subtree_html) %>
|
||||
<% if comment && comment.user && !should_be_hidden?(comment, @root_comment) %>
|
||||
<% if comment.depth < 3 %>
|
||||
<details class="comment-wrapper js-comment-wrapper comment-wrapper--deep-<%= comment.depth %> <%= comment_class(comment, is_view_root: is_view_root) %>" open>
|
||||
<summary>
|
||||
<span class="<% if comment.depth > 0 %>mx-0<% else %>m:mx-1<% end %> inline-block align-middle">
|
||||
<%= inline_svg_tag("collapse.svg", aria: true, class: "crayons-icon expanded", title: "Collapse") %>
|
||||
<%= inline_svg_tag("expand.svg", aria: true, class: "crayons-icon collapsed", title: "Expand") %>
|
||||
</span>
|
||||
<span class="js-collapse-comment-content inline-block align-middle"></span>
|
||||
</summary>
|
||||
<% end %>
|
||||
<div
|
||||
id="comment-node-<%= comment.id %>"
|
||||
class="
|
||||
comment single-comment-node
|
||||
<%= "low-quality-comment" if comment.decorate.low_quality %>
|
||||
<%= comment_class(comment, is_view_root: is_view_root) %>
|
||||
comment--deep-<%= comment.depth %>
|
||||
<%= "comment--too-deep" if comment.depth > 3 %>
|
||||
"
|
||||
data-comment-id="<%= comment.id %>"
|
||||
data-path="<%= commentable.path %>/comments/<%= comment.id_code_generated %>"
|
||||
data-comment-author-id="<%= comment_user_id_unless_deleted comment %>"
|
||||
data-content-user-id="<%= comment_user_id_unless_deleted comment %>">
|
||||
<%= render("comments/comment_proper",
|
||||
comment: comment,
|
||||
commentable: commentable,
|
||||
is_view_root: is_view_root,
|
||||
is_childless: is_childless,
|
||||
subtree_html: subtree_html) %>
|
||||
</div>
|
||||
<% if comment.depth < 3 %>
|
||||
</details>
|
||||
<% elsif !should_be_hidden?(comment, @root_comment) %>
|
||||
<%= render("comments/comment_proper",
|
||||
comment: comment,
|
||||
commentable: commentable,
|
||||
is_view_root: is_view_root,
|
||||
is_childless: is_childless,
|
||||
subtree_html: subtree_html) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
|
|||
9
app/views/comments/_comment_avatar.html.erb
Normal file
9
app/views/comments/_comment_avatar.html.erb
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<% if comment.deleted %>
|
||||
<span class="shrink-0 crayons-avatar <% if comment.depth == 0 %>m:crayons-avatar--l mt-4 m:mt-3<% else %>mt-4<% end %>">
|
||||
<%= image_tag(Images::Optimizer.call(SiteConfig.mascot_image_url, width: 32, height: 32, crop: "imagga_scale"), class: "crayons-avatar__image overflow-hidden", alt: "Sloan, the sloth mascot", loading: "lazy") %>
|
||||
</span>
|
||||
<% else %>
|
||||
<a href="<%= URL.user(comment.user) %>" class="shrink-0 crayons-avatar <% if comment.depth == 0 %>m:crayons-avatar--l mt-4 m:mt-3<% else %>mt-4<% end %>">
|
||||
<img class="crayons-avatar__image" width="32" height="32" src="<%= Images::Profile.call(comment.user.profile_image_url, length: 50) %>" alt="<%= comment.user.username %> profile image" />
|
||||
</a>
|
||||
<% end %>
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
<div class="comment-date">
|
||||
<a href="<%= decorated_comment.path %>">
|
||||
<time datetime="<%= decorated_comment.published_timestamp %>">
|
||||
<%= decorated_comment.readable_publish_date %>
|
||||
</time>
|
||||
</a>
|
||||
</div>
|
||||
<span class="color-base-30 px-2" role="presentation">•</span>
|
||||
<a href="<%= URL.comment(decorated_comment) %>" class="comment-date crayons-link crayons-link--secondary fs-s">
|
||||
<time datetime="<%= decorated_comment.published_timestamp %>">
|
||||
<%= decorated_comment.readable_publish_date %>
|
||||
</time>
|
||||
</a>
|
||||
|
|
|
|||
30
app/views/comments/_comment_footer.html.erb
Normal file
30
app/views/comments/_comment_footer.html.erb
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<footer class="comment__footer">
|
||||
<button
|
||||
class="crayons-btn crayons-btn--ghost crayons-btn--icon-left crayons-btn--s mr-1 reaction-like inline-flex reaction-button"
|
||||
id="button-for-comment-<%= comment.id %>"
|
||||
data-comment-id="<%= comment.id %>"
|
||||
title="heart">
|
||||
<%= inline_svg_tag("small-heart.svg", aria: true, class: "crayons-icon reaction-icon not-reacted", title: "Favorite heart outline button") %>
|
||||
<%= inline_svg_tag("small-heart-filled.svg", aria: true, class: "crayons-icon reaction-icon--like reaction-icon reacted", title: "Favorite heart outline button") %>
|
||||
<span class="reactions-count hidden"></span>
|
||||
<span class="reactions-label hidden m:inline-block">Like</span>
|
||||
</button>
|
||||
|
||||
<% if comment.depth < 2 || is_childless %>
|
||||
<a
|
||||
class="actions crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon-left toggle-reply-form mr-1 inline-flex"
|
||||
href="#<%= commentable.path %>/comments/new/<%= comment.id_code_generated %>"
|
||||
data-comment-id="<%= comment.id %>"
|
||||
data-path="<%= commentable.path %>/comments/<%= comment.id_code_generated %>"
|
||||
rel="nofollow">
|
||||
<%= inline_svg_tag("small-comment.svg", aria: true, class: "crayons-icon reaction-icon not-reacted", title: "Comment button") %>
|
||||
<span class="hidden m:inline-block">Reply</span>
|
||||
</a>
|
||||
<% else %>
|
||||
<span class="fs-s inline-flex items-center fs-italic color-base-50 pl-1">
|
||||
<%= inline_svg_tag("small-thread.svg", aria: true, class: "crayons-icon", title: "Thread") %>
|
||||
Thread
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
</footer>
|
||||
31
app/views/comments/_comment_header.html.erb
Normal file
31
app/views/comments/_comment_header.html.erb
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<header class="comment__header">
|
||||
<a href="<%= URL.user(comment.user) %>" class="crayons-link crayons-link--secondary flex items-center fw-medium">
|
||||
<span class="js-comment-username"><%= comment.user.name %></span>
|
||||
<% if commentable_author_is_op?(commentable, comment) %>
|
||||
<span class="crayons-tooltip inline-block spec-op-author -mr-2" data-tooltip="<%= get_ama_or_op_banner(commentable) %>">
|
||||
<%= inline_svg_tag("small-medal.svg", aria: true, class: "crayons-icon", title: get_ama_or_op_banner(commentable)) %>
|
||||
</span>
|
||||
<% end %>
|
||||
</a>
|
||||
|
||||
<%= render "comments/comment_date", decorated_comment: decorated_comment %>
|
||||
|
||||
<div class="comment__dropdown">
|
||||
<button class="dropbtn comment__dropdown-trigger crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon" aria-label="Toggle dropdown menu" aria-haspopup="true">
|
||||
<%= inline_svg_tag("small-overflow-horizontal.svg", aria: true, class: "crayons-icon pointer-events-none", title: "Dropdown menu") %>
|
||||
</button>
|
||||
<ul class="crayons-dropdown p-1 right-1 s:right-0 s:left-auto fs-base dropdown">
|
||||
<li><a href="<%= URL.comment(comment) %>" class="crayons-link crayons-link--block permalink-copybtn" aria-label="Copy link to <%= comment.user.name %>'s comment" data-no-instant>Copy link</a></li>
|
||||
<li class="comment-actions hidden" data-user-id="<%= comment.user_id %>" data-action="settings-button" data-path="<%= URL.comment(comment) %>/settings" aria-label="Go to <%= comment.user.name %>'s comment settings"></li>
|
||||
<% action = comment.hidden_by_commentable_user ? "Unhide" : "Hide" %>
|
||||
<li class="comment-actions hidden" data-action="hide-button" data-commentable-user-id="<%= commentable.user_id %>" data-user-id="<%= comment.user_id %>">
|
||||
<a href="#" class="crayons-link crayons-link--block hide-comment" data-hide-type="<%= action.downcase %>" data-comment-id="<%= comment.id %>" aria-label="<%= action %> <%= comment.user.name %>'s comment">
|
||||
<%= action %>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mod-actions hidden mod-actions-comment-button" data-path="<%= URL.comment(comment) %>/mod" aria-label="Moderate <%= comment.user.name %>'s comment"></li>
|
||||
<li class="report-abuse-link-wrapper" data-path="/report-abuse?url=<%= URL.comment(comment) %>" aria-label="Report <%= comment.user.name %>'s comment as abusive or violating our code of conduct and/or terms and conditions"></li>
|
||||
<li class="current-user-actions"></li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
|
@ -1,88 +1,39 @@
|
|||
<div class="comment-hash-marker" id="<%= comment.id_code_generated %>"></div>
|
||||
<div id="comment-node-<%= comment.id %>"
|
||||
class="single-comment-node <%= comment_class(comment, is_view_root: is_view_root) %> <%= "flat-node" if comment.depth > 3 %> comment-deep-<%= comment.depth %>" data-comment-id="<%= comment.id %>" data-comment-author-id="<%= comment_user_id_unless_deleted comment %>" data-content-user-id="<%= comment_user_id_unless_deleted comment %>">
|
||||
<% if comment.deleted %>
|
||||
<div class="inner-comment">
|
||||
<div class="body" style="padding-bottom:32px;opacity:0.3;user-select:none;cursor:default">
|
||||
[deleted]
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="inner-comment">
|
||||
<% decorated_comment = comment.decorate %>
|
||||
<% decorated_comment = comment.decorate %>
|
||||
|
||||
<% if decorated_comment.low_quality %>
|
||||
<div class="low-quality-comment-marker">
|
||||
<%= image_tag(Images::Optimizer.call(SiteConfig.mascot_image_url, width: 50, height: 50, crop: "imagga_scale"), class: "sloan", alt: "Sloan, the sloth mascot", loading: "lazy") %>
|
||||
Comment marked as low quality/non-constructive by the community
|
||||
<a href="/code-of-conduct">View code of conduct</a>
|
||||
<div class="comment__inner">
|
||||
<%= render partial: "comments/comment_avatar", locals: { comment: comment } %>
|
||||
|
||||
<div class="inner-comment comment__details">
|
||||
<div class="comment__content crayons-card">
|
||||
<% if comment.deleted %>
|
||||
<div class="p-6 align-center opacity-50 fs-s">
|
||||
<span class="js-comment-username">Comment deleted</span>
|
||||
</div>
|
||||
<% else %>
|
||||
<%= render partial: "comments/comment_quality_marker", locals: {
|
||||
comment: comment,
|
||||
decorated_comment: decorated_comment
|
||||
} %>
|
||||
|
||||
<%= render partial: "comments/comment_header", locals: {
|
||||
comment: comment,
|
||||
commentable: commentable,
|
||||
decorated_comment: decorated_comment
|
||||
} %>
|
||||
|
||||
<div class="comment__body text-styles text-styles--secondary body">
|
||||
<%= comment.safe_processed_html %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if comment.hidden_by_commentable_user %>
|
||||
<div class="low-quality-comment-marker">
|
||||
Comment hidden by post author - thread only visible in this permalink
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="details <%= "low-quality-comment" if decorated_comment.low_quality %>">
|
||||
<a href="/<%= comment.user.username %>">
|
||||
<img class="profile-pic" src="<%= Images::Profile.call(comment.user.profile_image_url, length: 50) %>" alt="<%= comment.user.username %> profile image" />
|
||||
<span class="comment-username">
|
||||
<span class="comment-username-inner">
|
||||
<%= comment.user.name %>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
<% if comment.user.twitter_username.present? %>
|
||||
<a href="https://twitter.com/<%= comment.user.twitter_username %>" rel="noopener noreferrer" target="_blank">
|
||||
<%= image_tag("twitter-logo.svg", class: "icon-img", alt: "twitter logo") %></a>
|
||||
<% end %>
|
||||
<% if comment.user.github_username.present? %>
|
||||
<a href="https://github.com/<%= comment.user.github_username %>" rel="noopener noreferrer" target="_blank">
|
||||
<%= image_tag("github-logo.svg", class: "icon-img", alt: "github logo") %>
|
||||
</a>
|
||||
<% end %>
|
||||
<% if commentable_author_is_op?(commentable, comment) %>
|
||||
<span class="op-marker"><%= get_ama_or_op_banner(commentable) %></span>
|
||||
<% end %>
|
||||
<%= render "comments/comment_date", decorated_comment: decorated_comment %>
|
||||
<button class="dropbtn" aria-label="Toggle dropdown menu">
|
||||
<%= inline_svg_tag("overflow-horizontal.svg", aria: true, class: "dropdown-icon", title: "Dropdown menu") %>
|
||||
</button>
|
||||
<div class="dropdown">
|
||||
<div class="crayons-dropdown p-1 right-1 left-1 s:right-0 s:left-auto fs-base">
|
||||
<a href="<%= comment.path %>" class="crayons-link crayons-link--block">Permalink</a>
|
||||
<a href="<%= comment.path %>" class="crayons-link crayons-link--block permalink-copybtn" data-no-instant>Copy Permalink</a>
|
||||
<span class="comment-actions hidden" data-user-id="<%= comment.user_id %>" data-action="settings-button" data-path="<%= comment.path %>/settings">
|
||||
</span>
|
||||
<% action = comment.hidden_by_commentable_user ? "Unhide" : "Hide" %>
|
||||
<span class="comment-actions hidden" data-action="hide-button" data-commentable-user-id="<%= commentable.user_id %>" data-user-id="<%= comment.user_id %>" style="display: none; width: 100%;">
|
||||
<a href="#" class="crayons-link crayons-link--block hide-comment" data-hide-type="<%= action.downcase %>" data-comment-id="<%= comment.id %>">
|
||||
<%= action %>
|
||||
</a>
|
||||
</span>
|
||||
<span class="mod-actions hidden mod-actions-comment-button" data-path="<%= comment.path %>/mod"></span>
|
||||
<span class="report-abuse-link-wrapper" data-path="/report-abuse?url=<%= comment_url(comment) %>"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="body <%= "low-quality-comment" if decorated_comment.low_quality %>">
|
||||
<%= comment.safe_processed_html %>
|
||||
<button class="reaction-button" id="button-for-comment-<%= comment.id %>" data-comment-id="<%= comment.id %>" title="heart">
|
||||
<%= image_tag("favorite-heart-outline-button.svg", alt: "Favorite heart outline button") %>
|
||||
<img class="voted-heart" src="<%= asset_path("emoji/emoji-one-heart.png") %>" alt="Favorite heart button" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="actions" data-comment-id="<%= comment.id %>" data-path="<%= commentable.path %>/comments/<%= comment.id_code_generated %>">
|
||||
<span class="current-user-actions hidden" style="display:none">
|
||||
</span>
|
||||
<% if comment.depth < 2 || is_childless %>
|
||||
<a href="#<%= commentable.path %>/comments/new/<%= comment.id_code_generated %>" class="toggle-reply-form" rel="nofollow">Reply</a>
|
||||
<% else %>
|
||||
<a href="#<%= commentable.path %>/comments/new/<%= comment.id_code_generated %>" class="toggle-reply-form thread-indication" rel="nofollow">Thread</a>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= subtree_html %>
|
||||
|
||||
<%= unless comment.deleted
|
||||
(render partial: "comments/comment_footer", locals: {
|
||||
comment: comment,
|
||||
commentable: commentable,
|
||||
is_childless: is_childless
|
||||
})
|
||||
end %>
|
||||
</div>
|
||||
</div>
|
||||
<%= subtree_html %>
|
||||
|
|
|
|||
14
app/views/comments/_comment_quality_marker.html.erb
Normal file
14
app/views/comments/_comment_quality_marker.html.erb
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<% if decorated_comment.low_quality %>
|
||||
<div class="low-quality-comment-marker comment__quality-marker">
|
||||
<%= inline_svg_tag("info.svg", aria: true, class: "crayons-icon mr-2", title: "Info") %>
|
||||
Comment marked as low quality/non-constructive by the community.
|
||||
<a href="/code-of-conduct">View code of conduct</a>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if comment.hidden_by_commentable_user %>
|
||||
<div class="low-quality-comment-marker comment__quality-marker">
|
||||
<%= inline_svg_tag("info.svg", aria: true, class: "crayons-icon mr-2", title: "Info") %>
|
||||
Comment hidden by post author - thread only visible in this permalink
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<div id="response-templates-data"></div>
|
||||
<div id="response-templates-data" class="hidden"></div>
|
||||
<%= javascript_packs_with_chunks_tag "validateFileInputs", "responseTemplates", defer: true %>
|
||||
|
||||
<% if @comment.errors.any? %>
|
||||
|
|
@ -28,8 +28,8 @@
|
|||
<%= f.hidden_field :parent_id, value: @parent_comment.id if @parent_comment %>
|
||||
<% end %>
|
||||
|
||||
<span class="crayons-avatar crayons-avatar--l mr-2 shrink-0">
|
||||
<img src="<%= Images::Optimizer.call(SiteConfig.logo_png, width: 256) %>" width="32" height="32" alt="pic" class="crayons-avatar__image" id="comment-primary-user-profile--avatar">
|
||||
<span class="crayons-avatar m:crayons-avatar--l mr-2 shrink-0">
|
||||
<img src="<%= Images::Optimizer.call(SiteConfig.logo_png, width: 256) %>" width="32" height="32" alt="pic" class="crayons-avatar__image overflow-hidden" id="comment-primary-user-profile--avatar">
|
||||
</span>
|
||||
<div class="comment-form__inner">
|
||||
<div class="comment-form__field">
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
<div class="container delete-confirm">
|
||||
|
||||
<h4><%= truncate(sanitize(@comment.processed_html, tags: []), length: 80) %></h4>
|
||||
<h1>Are you sure you want to delete this comment?</h1>
|
||||
<h2>You cannot undo this action, perhaps you just want to
|
||||
<a data-no-instant href="<%= @comment.path %>/edit">EDIT</a> instead?</h2>
|
||||
|
||||
<%= form_tag "/comments/#{@comment.id}", method: :delete do %>
|
||||
<button class="crayons-btn crayons-btn--danger">Delete</button>
|
||||
<% end %>
|
||||
<div class="crayons-layout crayons-layout--limited-l gap-0">
|
||||
<div class="crayons-card crayons-card--secondary text-styles text-styles--secondary text-padding -mb-1 mx-3 m:mx-6 mt-3">
|
||||
<%= truncate(sanitize(@comment.processed_html, tags: []), length: 200) %>
|
||||
</div>
|
||||
<div class="crayons-card text-padding">
|
||||
<h1 class="crayons-subtitle-1 mb-2">Are you sure you want to delete this comment?</h1>
|
||||
<p class="fs-l mb-4">
|
||||
You cannot undo this action, perhaps you just want to
|
||||
<a data-no-instant href="<%= @comment.path %>/edit">Edit</a> instead?
|
||||
</p>
|
||||
|
||||
<%= form_tag "/comments/#{@comment.id}", method: :delete do %>
|
||||
<button class="crayons-btn crayons-btn--danger">Delete</button>
|
||||
<a data-no-instant href="<%= @comment.path %>/edit" class="crayons-btn crayons-btn--secondary">Edit</a>
|
||||
<a data-no-instant href="<%= @comment.path %>" class="crayons-btn crayons-btn--ghost">Dismiss</a>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
<div class="single-comment-header"></div>
|
||||
<div class="comments-container comments-dedicated-page-container">
|
||||
<h3>Comment from a deleted article or podcast</h3>
|
||||
<div class="single-comment-node root">
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
<div
|
||||
class="comments-container comments-dedicated-page-container"
|
||||
id="comments-container"
|
||||
data-commentable-id="<%= @comment.commentable_id %>"
|
||||
data-commentable-type="<%= @comment.commentable_type %>">
|
||||
<h1 class="mb-6">Editing comment</h1>
|
||||
<%= render "form",
|
||||
commentable: @commentable,
|
||||
commentable_type: @comment.commentable_type %>
|
||||
<div class="crayons-layout crayons-layout--limited-l gap-0">
|
||||
<div
|
||||
class="comments-container crayons-card text-padding"
|
||||
id="comments-container"
|
||||
data-commentable-id="<%= @comment.commentable_id %>"
|
||||
data-commentable-type="<%= @comment.commentable_type %>">
|
||||
<h1 class="crayons-title mb-6">Editing comment</h1>
|
||||
<%= render "form",
|
||||
commentable: @commentable,
|
||||
commentable_type: @comment.commentable_type %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -37,96 +37,113 @@
|
|||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if @commentable.class.name == "Article" %>
|
||||
<%= render "shared/payment_pointer", user: @commentable.user %>
|
||||
<div id="comment-article-indicator" data-article-id="<%= @commentable.id %>">
|
||||
<% end %>
|
||||
<% if @root_comment %>
|
||||
<div class="single-comment-header"></div>
|
||||
<% else %>
|
||||
<div class="article-header">
|
||||
<a href="<%= @commentable.path %>" class="header-link">
|
||||
<% if @commentable.respond_to?(:main_image) && @commentable.main_image.present? %>
|
||||
<div class="picture" style="background-image:url(<%= cloud_cover_url(@commentable.main_image) %>)"></div>
|
||||
<% else %>
|
||||
<div class="blank-comment-space"></div>
|
||||
<% end %>
|
||||
<h3 id="comments-header"><%= @commentable.title %></h3>
|
||||
<h4>
|
||||
<%= @commentable.is_a?(PodcastEpisode) ? @commentable.podcast.name : @commentable.user.name %>
|
||||
<span class="published-at"><%= "on #{@commentable.published_at.strftime('%B %d, %Y')}" if @commentable.published_at %></span>
|
||||
</h4>
|
||||
</a>
|
||||
<% if @commentable.processed_html.present? %>
|
||||
<% if @commentable.processed_html.size < 350 %>
|
||||
<div class="body">
|
||||
<%= sanitize_rendered_markdown(@commentable.processed_html) %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="body">
|
||||
<%= truncate(sanitize(@commentable.processed_html, tags: []), length: 150) %>
|
||||
<a href="<%= @commentable.path %>"><span class="read-more">[Read Full]</span></a>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="comments-container comments-dedicated-page-container"
|
||||
id="comments-container"
|
||||
data-commentable-id="<%= @commentable.id %>"
|
||||
data-commentable-type="<%= @commentable.class.name %>">
|
||||
<% if @root_comment %>
|
||||
<div id="response-templates-data"></div>
|
||||
<%= javascript_packs_with_chunks_tag "responseTemplates", "fullScreenModeControl", defer: true %>
|
||||
<div class="top-level-actions">
|
||||
<h3>re: <%= @commentable.title %> <a href="<%= @commentable.path %>">VIEW POST</a></h3>
|
||||
<span class="comment-action-buttons">
|
||||
<% unless @root_comment.is_root? %>
|
||||
<a href="<%= @root_comment.root.path %>">TOP OF THREAD</a>
|
||||
<% end %>
|
||||
<a href="<%= @commentable.path %><%= user_signed_in? ? "/" : "#" %>comments">FULL DISCUSSION</a>
|
||||
</span>
|
||||
</div>
|
||||
<% else %>
|
||||
<%= render "form",
|
||||
commentable: @commentable,
|
||||
commentable_type: "Article" %>
|
||||
<div class="crayons-layout crayons-layout--limited-l gap-0">
|
||||
<% if @commentable.class.name == "Article" %>
|
||||
<%= render "shared/payment_pointer", user: @commentable.user %>
|
||||
<span id="comment-article-indicator" data-article-id="<%= @commentable.id %>"></span>
|
||||
<% end %>
|
||||
<div class="comment-trees" id="comment-trees-container">
|
||||
<% if @root_comment.present? %>
|
||||
<div class="root-comment">
|
||||
<% if @root_comment.depth > 0 && parent = @root_comment.parent %>
|
||||
<a href="<%= parent.path %>" class="comment-parent-link">
|
||||
re: <%= parent.title(150) %>
|
||||
</a>
|
||||
<% end %>
|
||||
<% cache ["comment_root-view-root_#{user_signed_in?}", @root_comment] do %>
|
||||
<%= tree_for(@root_comment, @root_comment.subtree.includes(:user).arrange[@root_comment], @commentable) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<% Comment.tree_for(@commentable).each do |comment, sub_comments| %>
|
||||
<% cache ["comment_root_#{user_signed_in?}", comment] do %>
|
||||
<%= tree_for(comment, sub_comments, @commentable) %>
|
||||
|
||||
<% unless @root_comment %>
|
||||
<article class="crayons-article crayons-card crayons-card--secondary s:mx-2 m:mx-4 -mb-1 z-0">
|
||||
<header class="crayons-article__header">
|
||||
<% if @commentable.respond_to?(:main_image) && @commentable.main_image.present? %>
|
||||
<div class="crayons-article__cover">
|
||||
<img src="<%= cloud_cover_url(@commentable.main_image) %>" width="1000" height="420" style="background-color:<%= @commentable.main_image_background_hex_color %>;" class="crayons-article__cover__image" alt="Cover image for <%= sanitize_and_decode @commentable.title %>">
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="crayons-article__header__meta">
|
||||
<h1 class="fs-2xl s:fs-3xl l:fs-4xl fw-bold s:fw-heavy lh-tight mb-1">
|
||||
<%= @commentable.title %>
|
||||
</h1>
|
||||
<p class="color-base-60">
|
||||
<%= @commentable.is_a?(PodcastEpisode) ? @commentable.podcast.name : @commentable.user.name %>
|
||||
<%= "on #{@commentable.published_at.strftime('%B %d, %Y')}" if @commentable.published_at %></span>
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<% if @commentable.processed_html.present? %>
|
||||
<div class="crayons-article__main">
|
||||
<div class="crayons-article__body text-styles -mt-1 m:-mt-2">
|
||||
<% if @commentable.processed_html.size < 350 %>
|
||||
<%= sanitize_rendered_markdown(@commentable.processed_html) %>
|
||||
<% else %>
|
||||
<%= truncate(sanitize(@commentable.processed_html, tags: []), length: 150) %>
|
||||
<div class="pt-6">
|
||||
<a class="crayons-btn crayons-btn--outlined" href="<%= @commentable.path %>">Read full post</a>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<center style="margin:30px 0px 22px;">
|
||||
<% if @commentable.any_comments_hidden %>
|
||||
<div class="fs-s color-base-60">
|
||||
<p>
|
||||
Some comments have been hidden by the post's author - <a href="/faq#what-does-comment-hidden-by-post-author-mean">find out more</a>
|
||||
</p>
|
||||
</article>
|
||||
<% else %>
|
||||
<div id="response-templates-data" class="hidden"></div>
|
||||
<%= javascript_packs_with_chunks_tag "responseTemplates", defer: true %>
|
||||
<header class="p-2 pb-4 m:p-6 m:pb-6 crayons-card crayons-card--secondary s:mx-2 m:mx-4 -mb-1 z-0">
|
||||
<h1 class="crayons-subtitle-1 mb-4">
|
||||
<span class="fw-normal color-base-60">Discussion on: </span>
|
||||
<%= @commentable.title %>
|
||||
</h1>
|
||||
<div class="flex">
|
||||
<a class="crayons-btn crayons-btn--outlined mr-2" href="<%= @commentable.path %>">View post</a>
|
||||
<a class="crayons-btn crayons-btn--outlined mr-2" href="<%= @commentable.path %><%= user_signed_in? ? "/" : "#" %>comments">Full discussion</a>
|
||||
</div>
|
||||
</header>
|
||||
<% end %>
|
||||
|
||||
<% if @root_comment.present? && (@root_comment.depth > 0 && parent = @root_comment.parent) %>
|
||||
<div class="p-2 pb-4 m:p-6 m:pb-6 crayons-card crayons-card--secondary s:mx-1 m:mx-2 -mb-2 z-0">
|
||||
<h2 class="crayons-subtitle-2 pb-2">
|
||||
<a href="<%= parent.path %>" class="crayons-link">
|
||||
<span class="fw-normal opacity-75">Replies for:</span> <%= parent.title(150) %>
|
||||
</a>
|
||||
</h2>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<section
|
||||
class="crayons-card text-padding min-w-0 z-elevate"
|
||||
id="comments-container"
|
||||
data-commentable-id="<%= @commentable.id %>"
|
||||
data-commentable-type="<%= @commentable.class.name %>">
|
||||
|
||||
<% unless @root_comment %>
|
||||
<%= render "form",
|
||||
commentable: @commentable,
|
||||
commentable_type: "Article" %>
|
||||
<% end %>
|
||||
|
||||
<div class="comments" id="comment-trees-container">
|
||||
<% if @root_comment.present? %>
|
||||
<% cache ["comment_root-view-root_#{user_signed_in?}", @root_comment] do %>
|
||||
<%= tree_for(@root_comment, @root_comment.subtree.includes(:user).arrange[@root_comment], @commentable) %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<% Comment.tree_for(@commentable).each do |comment, sub_comments| %>
|
||||
<% cache ["comment_root_#{user_signed_in?}", comment] do %>
|
||||
<%= tree_for(comment, sub_comments, @commentable) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if @commentable.any_comments_hidden %>
|
||||
<p class="mb-2 pt-6 fs-s align-center color-base-60">
|
||||
Some comments have been hidden by the post's author - <a href="/faq#what-does-comment-hidden-by-post-author-mean">find out more</a>
|
||||
</p>
|
||||
<% end %>
|
||||
</section>
|
||||
|
||||
<div class="py-6">
|
||||
<%= render "articles/conduct_and_abuse_actions", page: "comments_index" %>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
<% if has_vid?(@commentable) %>
|
||||
<%= render "articles/fitvids" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if has_vid?(@commentable) %>
|
||||
<%= render "articles/fitvids" %>
|
||||
<% end %>
|
||||
|
||||
<div class="fullscreen-code js-fullscreen-code"></div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,47 +1,36 @@
|
|||
<% title "Comment Settings" %>
|
||||
|
||||
<div class="crayons-layout crayons-layout--limited">
|
||||
<div class="crayons-layout crayons-layout--limited-m gap-0">
|
||||
<div class="crayons-card text-padding">
|
||||
<h1 class="pb-4">
|
||||
Comment Settings
|
||||
</h1>
|
||||
<h1 class="crayons-title mb-4">Comment Settings</h1>
|
||||
|
||||
<div class="comments-settings__row">
|
||||
<% if @notification_subscription.persisted? %>
|
||||
<div class="grid">
|
||||
<h4 class="comments-settings__row--title">
|
||||
Showing thread notifications
|
||||
</h4>
|
||||
<p class="comments-settings__row--subtitle">
|
||||
You will receive all notifications for this comment and any of your comments in this chain.
|
||||
</p>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="grid">
|
||||
<h4 class="comments-settings__row--title">
|
||||
Muting thread notifications
|
||||
</h4>
|
||||
<p class="comments-settings__row--subtitle">
|
||||
All notifications for this comment and any of your comments in the thread are currently muted.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="pr-4 m:pr-8 flex-1">
|
||||
<% if @notification_subscription.persisted? %>
|
||||
<p class="fw-bold">Showing thread notifications</p>
|
||||
<p class="fs-s color-base-60">You will receive all notifications for this comment and any of your comments in this chain.</p>
|
||||
<% else %>
|
||||
<p class="fw-bold">Muting thread notifications</p>
|
||||
<p class="fs-s color-base-60">All notifications for this comment and any of your comments in the thread are currently muted.</p>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= form_for(@notification_subscription, url: "/notification_subscriptions/Comment/#{@comment.id}", method: "post", html: { class: "mute-form shrink-0" }) do |f| %>
|
||||
<input type="hidden" name="config" value="<%= @notification_subscription.persisted? ? "not_subscribed" : "all_comments" %>">
|
||||
<%= f.submit @notification_subscription.persisted? ? "Mute notifications" : "Unmute notifications", class: "crayons-btn crayons-btn--secondary #{@notification_subscription.persisted? ? 'mute' : 'unmute'}" %>
|
||||
<% end %>
|
||||
|
||||
|
||||
<%= form_for(@notification_subscription, url: "/notification_subscriptions/Comment/#{@comment.id}", method: "post", html: { class: "mute-form" }) do |f| %>
|
||||
<input type="hidden" name="config" value="<%= @notification_subscription.persisted? ? "not_subscribed" : "all_comments" %>">
|
||||
<%= f.submit @notification_subscription.persisted? ? "Mute notifications" : "Unmute notifications", class: "crayons-btn #{@notification_subscription.persisted? ? 'mute' : 'unmute'}" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if NotificationSubscription.where(user_id: current_user, notifiable_type: "Article", notifiable_id: @comment.commentable_id, config: "all_comments").any? %>
|
||||
<p>
|
||||
You are still subscribed to all comments in the broader thread, which will mean you will still receive notifications for replies to this comment.
|
||||
</p>
|
||||
<%= form_for(@notification_subscription, url: "/notification_subscriptions/Article/#{@comment.commentable_id}", method: "post", html: { class: "mute-form" }) do |f| %>
|
||||
<input type="hidden" name="config" value="not_subscribed">
|
||||
<%= f.submit "Unsubscribe from parent post", class: "crayons-btn crayons-btn--secondary" %>
|
||||
<% end %>
|
||||
<div class="flex pt-6">
|
||||
<div class="pr-4 m:pr-8 flex-1">
|
||||
<p class="fw-bold">Subscription</p>
|
||||
<p class="fs-s color-base-60">You are still subscribed to all comments in the broader thread, which will mean you will still receive notifications for replies to this comment.</p>
|
||||
</div>
|
||||
<%= form_for(@notification_subscription, url: "/notification_subscriptions/Article/#{@comment.commentable_id}", method: "post", html: { class: "mute-form" }) do |f| %>
|
||||
<input type="hidden" name="config" value="not_subscribed">
|
||||
<%= f.submit "Unsubscribe from parent post", class: "crayons-btn crayons-btn--secondary" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,24 @@
|
|||
<%= javascript_include_tag "application" %>
|
||||
|
||||
<div class="container delete-confirm">
|
||||
<h4><%= @listing.title %></h4>
|
||||
<h1>Are you sure you want to delete this listing?</h1>
|
||||
<div class="crayons-layout crayons-layout--limited-l gap-0">
|
||||
<div class="crayons-card crayons-card--secondary text-styles text-styles--secondary text-padding -mb-1 mx-3 m:mx-6 mt-3">
|
||||
<%= @listing.title %>
|
||||
</div>
|
||||
<div class="crayons-card text-padding">
|
||||
<h1 class="crayons-subtitle-1 mb-2">Are you sure you want to delete this listing?</h1>
|
||||
<p class="fs-l mb-4">
|
||||
You cannot undo this action, perhaps you just want to
|
||||
<a data-no-instant href="/listings/<%= @listing.id %>/edit">
|
||||
<%= @listing.published ? "unpublish" : "edit" %>
|
||||
</a>
|
||||
instead?
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
You cannot undo this action, perhaps you just want to
|
||||
<a data-no-instant href="/listings/<%= @listing.id %>/edit">
|
||||
<%= @listing.published ? "unpublish" : "edit" %>
|
||||
</a>
|
||||
instead?
|
||||
</h2>
|
||||
|
||||
<%= form_tag "/listings/#{@listing.id}", method: :delete do %>
|
||||
<button class="crayons-btn crayons-btn--danger">Delete</button>
|
||||
<% end %>
|
||||
<%= form_tag "/listings/#{@listing.id}", method: :delete do %>
|
||||
<button class="crayons-btn crayons-btn--danger">Delete</button>
|
||||
<a data-no-instant href="/listings/<%= @listing.id %>/edit" class="crayons-btn crayons-btn--secondary">
|
||||
<%= @article.published ? "Unpublish" : "Edit" %>
|
||||
</a>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@
|
|||
<%= f.hidden_field :commentable_type, value: json_data["comment"]["commentable"]["class"]["name"] %>
|
||||
|
||||
<%= f.hidden_field :parent_id, value: json_data["comment"]["id"] %>
|
||||
<%= f.text_area :body_markdown, id: "comment-textarea-for-#{json_data['comment']['id']}", class: "crayons-textfield mb-2", placeholder: "Reply..." %>
|
||||
<%= f.text_area :body_markdown, id: "comment-textarea-for-#{json_data['comment']['id']}", class: "crayons-textfield mb-2", placeholder: "Reply...", 'aria-label': "Reply to a comment..." %>
|
||||
<div class="actions">
|
||||
<button type="submit" class="crayons-btn comment-action-button" onclick="validateField(event)">Submit</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -73,34 +73,37 @@
|
|||
</p>
|
||||
</center>
|
||||
<% end %>
|
||||
<div class="container">
|
||||
<div class="body">
|
||||
<% if @episode.podcast.feed_url.include?("soundcloud") %>
|
||||
<%= simple_format((@episode.processed_html || @episode.body), sanitize: true) %>
|
||||
<% else %>
|
||||
<%= sanitize (@episode.processed_html || ""),
|
||||
tags: %w[strong br em a table tbody thead tfoot th tr td col colgroup del p h1 h2 h3 h4 h5 h6 blockquote time div span i em u b ul ol li dd dl dt q code pre img sup cite center small],
|
||||
attributes: %w[href strong em class ref rel src title alt colspan height width size rowspan span value start data-conversation data-lang id] %>
|
||||
<% end %>
|
||||
<p style="font-size:16px;">
|
||||
<a href="<%= @episode.website_url %>">Episode source</a>
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="comments-container"
|
||||
id="comments-container"
|
||||
data-commentable-id="<%= @episode.id %>"
|
||||
data-commentable-type="PodcastEpisode">
|
||||
<%= render "/comments/form",
|
||||
commentable: @episode,
|
||||
commentable_type: "PodcastEpisode" %>
|
||||
<div class="comment-trees" id="comment-trees-container">
|
||||
<% Comment.tree_for(@episode, 12).each do |comment, sub_comments| %>
|
||||
<% cache ["comment_root_#{user_signed_in?}", comment] do %>
|
||||
<%= tree_for(comment, sub_comments, @episode) %>
|
||||
<% end %>
|
||||
|
||||
<div class="crayons-layout crayons-layout--limited-l gap-0">
|
||||
<div class="crayons-card">
|
||||
<div class="text-padding text-styles">
|
||||
<% if @episode.podcast.feed_url.include?("soundcloud") %>
|
||||
<%= simple_format((@episode.processed_html || @episode.body), sanitize: true) %>
|
||||
<% else %>
|
||||
<%= sanitize (@episode.processed_html || ""),
|
||||
tags: %w[strong br em a table tbody thead tfoot th tr td col colgroup del p h1 h2 h3 h4 h5 h6 blockquote time div span i em u b ul ol li dd dl dt q code pre img sup cite center small],
|
||||
attributes: %w[href strong em class ref rel src title alt colspan height width size rowspan span value start data-conversation data-lang id] %>
|
||||
<% end %>
|
||||
|
||||
<p><a href="<%= @episode.website_url %>">Episode source</a></p>
|
||||
</div>
|
||||
|
||||
<section
|
||||
class="comments-container text-padding"
|
||||
id="comments-container"
|
||||
data-commentable-id="<%= @episode.id %>"
|
||||
data-commentable-type="PodcastEpisode">
|
||||
<%= render "/comments/form",
|
||||
commentable: @episode,
|
||||
commentable_type: "PodcastEpisode" %>
|
||||
<div class="comment-trees" id="comment-trees-container">
|
||||
<% Comment.tree_for(@episode, 12).each do |comment, sub_comments| %>
|
||||
<% cache ["comment_root_#{user_signed_in?}", comment] do %>
|
||||
<%= tree_for(comment, sub_comments, @episode) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ RSpec.describe "Comments", type: :request do
|
|||
|
||||
it "displays full discussion text" do
|
||||
get comment.path
|
||||
expect(response.body).to include("FULL DISCUSSION")
|
||||
expect(response.body).to include("Full discussion")
|
||||
end
|
||||
|
||||
it "renders user payment pointer if set" do
|
||||
|
|
@ -37,11 +37,6 @@ RSpec.describe "Comments", type: :request do
|
|||
end
|
||||
|
||||
context "when the comment is a root" do
|
||||
it "does not display top of thread button" do
|
||||
get comment.path
|
||||
expect(response.body).not_to include("TOP OF THREAD")
|
||||
end
|
||||
|
||||
it "displays the comment hidden message if the comment is hidden" do
|
||||
comment.update(hidden_by_commentable_user: true)
|
||||
get comment.path
|
||||
|
|
@ -61,7 +56,6 @@ RSpec.describe "Comments", type: :request do
|
|||
|
||||
it "displays proper button and text for child comment" do
|
||||
get child.path
|
||||
expect(response.body).to include("TOP OF THREAD")
|
||||
expect(response.body).to include(CGI.escapeHTML(comment.title(150)))
|
||||
expect(response.body).to include(child.processed_html)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ RSpec.describe "Editing A Comment", type: :system, js: true do
|
|||
visit article.path.to_s
|
||||
wait_for_javascript
|
||||
|
||||
click_on(class: 'comment__dropdown-trigger')
|
||||
click_link("Edit")
|
||||
assert_updated
|
||||
end
|
||||
|
|
@ -41,6 +42,7 @@ RSpec.describe "Editing A Comment", type: :system, js: true do
|
|||
|
||||
wait_for_javascript
|
||||
|
||||
click_on(class: 'comment__dropdown-trigger')
|
||||
click_link("Edit")
|
||||
assert_updated
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,12 +22,11 @@ RSpec.describe "Visiting article comments", type: :system, js: true do
|
|||
end
|
||||
|
||||
it "displays child comments" do
|
||||
expect(page).to have_selector(".comment-deep-1", visible: :visible, count: 3)
|
||||
expect(page).to have_selector(".comment--deep-1", visible: :visible, count: 3)
|
||||
end
|
||||
|
||||
it "displays grandchild comments" do
|
||||
expect(page).to have_selector("#comment-node-#{grandchild_comment.id}.comment-deep-2", visible: :visible,
|
||||
count: 1)
|
||||
expect(page).to have_selector(".comment--deep-2#comment-node-#{grandchild_comment.id}", visible: :visible, count: 1)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -39,12 +38,11 @@ RSpec.describe "Visiting article comments", type: :system, js: true do
|
|||
end
|
||||
|
||||
it "displays child comments" do
|
||||
expect(page).to have_selector(".comment-deep-1", visible: :visible, count: 2)
|
||||
expect(page).to have_selector(".comment--deep-1", visible: :visible, count: 2)
|
||||
end
|
||||
|
||||
it "displays grandchild comments" do
|
||||
expect(page).to have_selector("#comment-node-#{grandchild_comment.id}.comment-deep-2", visible: :visible,
|
||||
count: 1)
|
||||
expect(page).to have_selector(".comment--deep-2#comment-node-#{grandchild_comment.id}", visible: :visible, count: 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -86,8 +86,8 @@ RSpec.describe "User visits podcast show page", type: :system, js: true do
|
|||
it "sees the comments", js: true do
|
||||
visit podcast_episode.path.to_s
|
||||
|
||||
expect(page).to have_selector(".comment-deep-0#comment-node-#{comment.id}", visible: :visible, count: 1)
|
||||
expect(page).to have_selector(".comment-deep-1#comment-node-#{comment2.id}", visible: :visible, count: 1)
|
||||
expect(page).to have_selector(".comment--deep-0#comment-node-#{comment.id}", visible: :visible, count: 1)
|
||||
expect(page).to have_selector(".comment--deep-1#comment-node-#{comment2.id}", visible: :visible, count: 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ RSpec.describe "Views an article", type: :system, js: true do
|
|||
visit "#{article.path}/comments"
|
||||
|
||||
expect(page).to have_selector(".single-comment-node", visible: :visible, count: 3)
|
||||
expect(page).not_to have_selector(".op-marker")
|
||||
expect(page).not_to have_selector(".spec-op-author")
|
||||
end
|
||||
|
||||
it "shows op marker on author and co-author comments" do
|
||||
|
|
@ -22,21 +22,21 @@ RSpec.describe "Views an article", type: :system, js: true do
|
|||
create(:comment, user: co_author, commentable: article)
|
||||
visit "#{article.path}/comments"
|
||||
|
||||
expect(page).to have_selector(".op-marker", visible: :visible, text: "Author", count: 2)
|
||||
expect(page).to have_selector(".spec-op-author", visible: :visible, text: "Author", count: 2)
|
||||
end
|
||||
|
||||
it "shows special op marker on ama articles" do
|
||||
create(:comment, user: user, commentable: ama_article)
|
||||
visit "#{ama_article.path}/comments"
|
||||
|
||||
expect(page).to have_selector(".op-marker", visible: :visible, text: "Ask Me Anything")
|
||||
expect(page).to have_selector(".spec-op-author", visible: :visible, text: "Ask Me Anything")
|
||||
end
|
||||
|
||||
it "shows a thread" do
|
||||
visit "#{article.path}/comments/#{comment.id_code_generated}"
|
||||
|
||||
expect(page).to have_selector(".single-comment-node", visible: :visible, count: 2)
|
||||
expect(page).to have_selector(".comment-deep-0#comment-node-#{comment.id}", visible: :visible, count: 1)
|
||||
expect(page).to have_selector(".comment-deep-1#comment-node-#{child_comment.id}", visible: :visible, count: 1)
|
||||
expect(page).to have_selector(".comment--deep-0#comment-node-#{comment.id}", visible: :visible, count: 1)
|
||||
expect(page).to have_selector(".comment--deep-1#comment-node-#{child_comment.id}", visible: :visible, count: 1)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,9 +15,7 @@ RSpec.describe "rendering locals in a partial", type: :view do
|
|||
subtree_html: ""
|
||||
|
||||
expect(rendered).to match(/low-quality-comment-marker/)
|
||||
.and match(/low-quality-comment/)
|
||||
.and match(/sloan/)
|
||||
.and match(%r{Comment marked as low quality/non-constructive by the community})
|
||||
.and match(%r{Comment marked as low quality/non-constructive by the community.})
|
||||
expect(rendered).to have_link "View code of conduct", href: "/code-of-conduct"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue