Notifications redesign (#11084)

* notifications

* fix

* .

* REVERT

* .

* drop ccss

* REVERT

* specs

* drop colons

* fixse

* fix

* spec 1

* eh

* Fix notification specs

Co-authored-by: Molly Struve <mollylbs@gmail.com>
This commit is contained in:
ludwiczakpawel 2020-10-29 20:38:17 +01:00 committed by GitHub
parent e00cb5df17
commit 5d3691bcc5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 681 additions and 1073 deletions

View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5 5h3a6 6 0 110 12v2.625c-3.75-1.5-9-3.75-9-8.625a6 6 0 016-6z"/>
</svg>

After

Width:  |  Height:  |  Size: 174 B

View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<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>

After

Width:  |  Height:  |  Size: 245 B

View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M16.773 14.652l-1.06-1.062 1.06-1.06a3.751 3.751 0 10-5.303-5.304l-1.06 1.061-1.062-1.06 1.062-1.06a5.25 5.25 0 117.425 7.425l-1.061 1.06h-.001zm-2.121 2.121l-1.061 1.06a5.25 5.25 0 11-7.425-7.424l1.061-1.061 1.06 1.062-1.06 1.06a3.75 3.75 0 105.303 5.304l1.06-1.06 1.062 1.06v-.001zm-.531-7.955l1.061 1.061-5.303 5.303-1.061-1.061 5.303-5.303z"/>
</svg>

After

Width:  |  Height:  |  Size: 452 B

View file

@ -109,8 +109,9 @@ function initReactions() {
var thisButt = this;
document
.getElementById('comment-form-for-' + thisButt.dataset.reactableId)
.classList.add('showing');
thisButt.innerHTML = '';
.classList.remove('hidden');
thisButt.classList.add('hidden');
thisButt.classList.remove('inline-flex');
setTimeout(function () {
document
.getElementById(

View file

@ -238,7 +238,7 @@ function handleCommentSubmit(event) {
}
else if (document.getElementById("notifications-container")) {
var newDiv = document.createElement("span")
newDiv.innerHTML = '<div class="reply-sent-notice">Reply sent — <a href="' + newComment.url + '">Check it out</a></div>'
newDiv.innerHTML = '<div class="crayons-notice align-center p-2 m-2 crayons-notice--success reply-sent-notice reply-sent-notice">Reply sent — <a href="' + newComment.url + '">Check it out</a></div>'
form.replaceWith(newDiv);
}
else {

View file

@ -47,6 +47,14 @@
width: var(--layout-sidebar-right-width);
}
&__content {
// Hack preventing content exceeding its container - it works for scenarios where we have
// `pre` tag having wide (overflowing) text. And the container itself is part of a layout
// built using CSS `grid`. Without this, the grid layout wouldn't stick to its defined
// widths...
min-width: 0;
}
&__content__inner {
margin: 0 auto;
width: 100%;

View file

@ -5,6 +5,7 @@
--content-rythm: var(--su-2);
--content-font-size: var(--fs-l);
--content-secondary-font-size: var(--fs-base);
--content-tertiary-font-size: var(--fs-base);
@media (min-width: $breakpoint-s) {
--content-secondary-font-size: var(--fs-l);
@ -72,6 +73,10 @@ body {
font-size: var(--content-secondary-font-size);
}
&--tertiary {
font-size: var(--content-tertiary-font-size);
}
a {
&.anchor {
padding-top: 0;

View file

@ -13,6 +13,11 @@
box-shadow: 0 0 0 1px var(--card-secondary-border);
}
&--elevated {
box-shadow: 0 0 0 1px var(--card-secondary-border), 0 1px 3px var(--base-a5),
0 3px 9px var(--base-a5);
}
&__header {
padding: var(--su-3) var(--su-4);
border-bottom: 1px solid var(--body-bg);

View file

@ -223,4 +223,6 @@
--reaction-custom-bg: var(--accent-success-a10);
--reaction-save-color: var(--accent-brand);
--reaction-save-bg: var(--accent-brand-a10);
--reaction-comment-color: var(--accent-warning);
--reaction-comment-bg: var(--accent-warning-a10);
}

View file

@ -11,8 +11,6 @@
@import 'podcast-form';
@import 'user-profile-header';
@import 'comments';
@import 'notifications';
@import 'notifications-welcome-broadcast';
@import 'live';
@import 'preact/sidebar-widget';
@import 'preact/article-form';

View file

@ -1,20 +0,0 @@
// TODO: [@forem/delightful]: Refactor nesting in this file
// in addition to notifications.scss so that the nesting is
// not as deep as it currently is
.notifications-index {
.home {
.articles-list {
.single-article {
.content {
&.broadcast-content {
.opt-out {
padding-top: 24px;
font-size: 12px;
font-style: italic;
}
}
}
}
}
}
}

View file

@ -1,603 +0,0 @@
@import 'variables';
@import 'mixins';
@import 'functions';
@import 'config/import';
.notifications-index {
.home {
overflow: initial;
.articles-list {
.signup-cue {
padding: 30px 25px;
background: white;
border-radius: 6px;
box-shadow: 0px 3px 9px #d4dce4;
hr {
margin: 30px auto 15px;
}
a.sign-up-link {
display: inline-block;
border: 1px solid $medium-gray;
padding: 4px 8px;
border-radius: 3px;
margin: 20px 6px;
img {
width: 18px;
vertical-align: -1px;
}
}
}
// TODO: [@forem/delightful]: Remove .signup-cue-advanced and .sloan
// from stylesheet since it does not appear to be used anywhere
.signup-cue-advanced {
text-align: left;
padding: 30px 25px;
.sloan {
height: calc(5vw + 200px);
margin: 10px auto 30px;
display: block;
}
}
.single-article {
.reaction-images {
display: inline-block;
}
.reaction-image {
width: 21px;
height: 21px;
vertical-align: -4px;
}
.content {
padding-bottom: 18px;
line-height: 1.35em;
&.notification-content {
a {
color: $sky-blue;
font-weight: 500;
}
}
&.reaction-content {
width: calc(100% - 145px);
}
&.badge-content {
margin: auto;
width: 98%;
display: block;
text-align: center;
.badge-title {
margin: 6px auto;
width: 90%;
font-size: 1.3em;
}
p.badge-description {
margin: 10px auto;
width: 90%;
@include themeable(color, theme-secondary-color, #666666);
&.milestone-emojis {
font-size: xx-large;
padding-top: 10px;
padding-bottom: 0px;
}
}
img.badge-image {
margin: 10px 0px 20px;
height: 150px;
}
img.milestone-gif {
margin: 10px 0px 10px;
border-radius: 8px;
width: 300px;
}
hr.minimal-divider {
width: 90px;
opacity: 0.4;
margin: 18px auto 22px;
}
p.badge-reward-message {
margin: 8px auto;
width: 90%;
color: var(--body-color);
}
p.badge-credit-message {
margin: 8px auto;
width: 100%;
color: var(--body-color);
font-size: 0.94em;
line-height: 1.35em;
strong a {
font-weight: 700;
}
}
}
.follow-action-button {
display: block;
color: white;
background: $sky-blue;
border: 2px solid $sky-blue;
border-radius: 3px;
font-size: 1.1em;
margin-top: 0.3em;
padding: 2px 10px;
min-height: 33px;
min-width: 150px;
&.following-butt {
background: $sky-blue;
color: white;
}
&:hover {
border: 2px solid darken($sky-blue, 5%);
}
&.badge-button {
margin-bottom: 12px;
display: inline-block;
}
}
.mod-instructions {
font-size: 0.9em;
background: darken($light-gray, 1%);
border: 1px solid darken($light-gray, 12%);
width: 80%;
padding: 10px 0px 10px 35px;
border-radius: 3px;
}
.notification-comment-reacted-link {
vertical-align: middle;
padding: 2px 6px;
border: 1px solid lighten($medium-gray, 9%);
border-radius: 3px;
max-width: 100%;
display: inline-block;
margin-bottom: 3px;
overflow: hidden;
text-overflow: ellipsis;
&:hover {
@include themeable(
background,
theme-container-background-hover,
lighten($blue, 57%)
);
border: 1px solid lighten($sky-blue, 17%);
}
}
.notification-new-post {
padding: 12px 10px;
margin-top: 10px;
border: 1px solid lighten($dark-gray, 18%);
border-radius: 3px;
color: var(--body-color);
position: relative;
.notification-new-post-title {
font-size: 1.7em;
word-wrap: break-word;
line-height: 1.06em;
}
.notification-new-post-tags {
margin-top: 6px;
@include themeable(color, theme-color, $medium-gray);
}
}
.footnote {
font-size: 0.8em;
opacity: 0.9;
}
.follower-pic-row {
display: inline-block;
}
}
.comment-link-wrapper {
display: block;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.comment-text {
padding: 10px;
margin-top: 10px;
border: 1px solid lighten($dark-gray, 18%);
border-radius: 3px;
color: var(--body-color);
position: relative;
.comment-text-header {
display: block;
padding: 5px 10px;
margin-left: -10px;
margin-top: -10px;
margin-bottom: 8px;
border-bottom: 1px solid lighten($dark-gray, 18%);
width: 100%;
font-weight: bold;
font-size: 0.76em;
position: relative;
z-index: 6;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@include themeable(
background,
theme-container-accent-background,
lighten($lightest-gray, 1%)
);
}
&:hover {
border: 1px solid $black;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: 1.2em;
}
p {
color: var(--body-color);
width: 99%;
padding: 0;
margin-left: 0;
}
img {
max-width: 100%;
max-height: 400px;
}
blockquote {
border-left: calc(0.2vw + 2px) solid $dark-gray;
padding: 0.1% 6% 0.1% 2%;
margin-left: 0.5rem;
}
}
.comment-actions {
position: relative;
button {
background: transparent;
border: 0px;
margin-top: 5px;
margin-left: -5px;
margin-right: 3px;
height: 30px;
width: 45px;
padding: 3px 0px;
overflow-y: hidden;
-webkit-appearance: none;
.reacted-emoji {
display: none;
}
&.readinglist-button {
background: darken($purple, 26%);
color: white;
font-family: $helvetica-condensed;
height: auto;
width: auto;
padding: 3px 7px;
display: inline-block;
vertical-align: 5px;
font-size: 17px;
border-radius: 3px;
float: right;
img {
opacity: 1;
}
&.reacted {
vertical-align: 0px;
padding: 3px 7px 1px;
}
}
&.reacted {
background: transparent;
.reacted-emoji {
display: inline;
}
.reaction-button-text {
display: none;
}
img {
display: none;
}
}
}
img {
height: 25px;
width: 25px;
opacity: 0.7;
&:hover {
opacity: 1;
}
}
.toggle-reply-form {
position: absolute;
right: 5px;
bottom: 8px;
font-weight: 300;
font-family: $helvetica-condensed;
font-stretch: condensed;
color: $bold-blue;
&.already-replied-link {
color: $green;
}
}
}
.reply-sent-notice {
@include themeable(
background,
theme-container-background,
$light-green
);
text-align: center;
padding: 10px 0px;
a {
display: inline-block;
background: $green;
color: white !important;
padding: 3px 8px;
border-radius: 3px;
}
}
form {
width: 104%;
background: $light-gray;
overflow: auto;
position: relative;
margin-bottom: calc(0.8vw - 6px);
z-index: 4;
margin-left: -2%;
border-top: 1px solid $light-medium-gray;
text-align: right;
display: none;
margin-top: 4px;
@include themeable(
background,
theme-container-accent-background,
$light-gray
);
&.showing {
display: block;
}
&.submitting {
input[type='submit'] {
background: #00bbff;
}
textarea {
color: lighten($dark-gray, 25%);
border: 1px solid $light-green;
background: #fff url(image-src('loading-ellipsis.svg')) no-repeat
center center;
background-size: 50px;
}
}
@media screen and (min-width: 820px) {
width: 100%;
margin-left: 0%;
border-radius: 3px;
@include themeable(
border,
theme-container-border,
1px solid rgb(232, 229, 229)
);
}
.field {
margin-bottom: 0px;
}
textarea {
width: 92%;
margin: 15px auto 2px;
display: block;
resize: none;
border-radius: 3px;
height: 55px;
font-size: 16px;
padding: 6px;
transition: height 0.3s ease;
height: calc(2vw + 120px);
@include themeable(
border,
theme-container-background,
1px solid rgb(232, 229, 229)
);
background: var(--card-bg);
color: var(--body-color);
}
input[type='submit'] {
margin-right: 15px;
background: rgb(0, 146, 228);
color: white;
border: 0px;
font-size: 11px;
font-weight: 500;
margin-top: 3px;
padding: 5px 12px;
border-radius: 3px;
appearance: none;
}
}
}
.single-notification {
cursor: default;
}
.unseen {
@include themeable(
background,
theme-container-accent-background,
$light-purple
);
}
}
}
.load-more-wrapper {
clear: both;
@include load-more;
}
}
.notification-nav {
margin-bottom: var(--su-4);
&:last-child {
margin-bottom: 0;
}
header {
color: var(--base-80);
}
.crayons-link {
margin-bottom: var(--su-1);
&:last-child {
margin-bottom: 0;
}
}
}
.notifications-filter__list {
li {
margin-bottom: var(--su-1);
&:last-child {
margin-bottom: 0;
}
}
&--item {
align-items: center;
border-radius: var(--radius);
box-sizing: border-box;
color: var(--card-color);
display: inline-flex;
font-weight: var(--fw-medium);
justify-content: space-between;
padding: var(--su-2);
width: 100%;
&:hover {
background: var(--base-10);
}
&.selected {
background: var(--base-10);
.notifications-filter__icon {
visibility: visible;
}
}
}
}
.notifications-filter__dropdown {
display: none;
@media screen and (max-width: 950px) {
display: block;
}
&__menu-overlay {
display: none;
&.showing {
display: flex;
}
&:before {
content: '';
position: fixed;
left: 0;
right: 0;
top: 0;
right: 0;
height: 100%;
width: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 499;
}
}
&__header {
padding: var(--su-3) var(--su-4);
}
&__title {
font-weight: var(--fw-bold);
}
&__menu {
display: flex;
background: var(--base-inverted);
flex-direction: column;
position: absolute;
width: 100%;
left: 0;
right: 0;
z-index: 500;
}
&__select {
appearance: none;
border: none;
display: flex;
align-items: center;
padding: var(--su-4);
justify-content: center;
font-weight: var(--fw-bold);
width: 100%;
font-family: var(--ff-sans-serif);
&:hover &:active {
background-color: var(--base-10);
}
}
&__icon {
visibility: hidden;
}
&__option {
align-items: center;
display: flex;
justify-content: space-between;
padding: var(--su-3) var(--su-4);
&:hover,
&:active,
&:focus {
background-color: var(--base-10);
}
&.selected {
}
}
&__label {
display: flex;
flex-direction: column;
align-items: baseline;
}
&__label--title {
font-weight: var(--fw-medium);
font-size: var(--fs-base);
}
&__label--subtitle {
color: var(--base-60);
font-size: var(--fs-s);
}
}
.notifications-filter__list,
.notifications-filter__dropdown {
.notifications-filter__icon {
visibility: hidden;
}
.selected {
.notifications-filter__icon {
visibility: visible;
}
}
}

View file

@ -4,6 +4,7 @@
@import 'views/footer';
@import 'views/listings';
@import 'views/dashboard';
@import 'views/notifications';
@import 'views/profile';
@import 'views/mod-actions';
@import 'views/mod-center';

View file

@ -0,0 +1,167 @@
@import '../config/import';
.notification {
--unseen-border-width: 0px;
--padding: var(--su-3);
padding: var(--padding);
padding-left: calc(var(--padding) - var(--unseen-border-width));
display: flex;
color: var(--base-80);
border-radius: 0;
@media (min-width: $breakpoint-s) {
--padding: var(--su-4);
}
@media (min-width: $breakpoint-m) {
--padding: var(--su-5);
border-radius: var(--radius);
}
&--middle {
align-items: center;
}
&--promoted {
text-align: center;
flex-direction: column;
align-items: center;
padding: var(--su-5);
@media (min-width: $breakpoint-m) {
padding: var(--su-8);
}
}
&__content {
padding-left: var(--su-4);
flex: 1 auto;
// Hack preventing content exceeding its container - it works for scenarios where we have
// `pre` tag having wide (overflowing) text. And the container itself is part of a layout
// built using CSS `grid`. Without this, the grid layout wouldn't stick to its defined
// widths...
min-width: 0;
}
&__mod-controls {
padding: var(--su-1);
display: flex;
align-items: center;
font-size: var(--fs-s);
position: absolute;
right: calc(var(--su-2) * -1);
top: calc(var(--su-3) * -1);
border-radius: 9999px;
}
&__actions {
border-top: 1px solid var(--base-10);
padding-top: var(--su-1);
display: flex;
}
&__reply-title {
border-radius: var(--radius) var(--radius) 0 0;
margin-bottom: var(--su-1);
padding: var(--su-2) var(--su-3);
font-size: var(--fs-s);
background: var(--base-a5);
margin-left: var(--su-2);
display: inline-block;
max-width: 80%;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
vertical-align: middle;
font-weight: var(--fw-medium);
}
&__preview {
padding: var(--su-1);
&__title {
font-size: var(--fs-xl);
line-height: var(--lh-tight);
margin-bottom: var(--su-2);
@media (min-width: $breakpoint-m) {
font-size: var(--fs-2xl);
}
}
}
.unseen & {
--unseen-border-width: 4px;
@media (min-width: $breakpoint-l) {
--unseen-border-width: 8px;
}
border-left: var(--unseen-border-width) solid var(--accent-brand);
}
}
//////////////////////////////////////////////
// TODO: /////////////////////////////////////
//////////////////////////////////////////////
// //
// Dear Paweł, //
// You can do it better. //
// //
// Sincerely yours, Paweł. //
// //
//////////////////////////////////////////////
.reaction-icon--like {
color: var(--reaction-like-color);
}
.reaction-icon--unicorn {
color: var(--reaction-custom-color);
}
.reaction-icon--readinglist {
color: var(--reaction-save-color);
}
.reaction-icon--comment {
color: var(--reaction-comment-color);
}
.crayons-btn--ghost {
&.reaction-like {
&.reacted {
--bg: var(--reaction-like-bg);
--bg-hover: var(--reaction-like-bg);
}
}
&.reaction-comment {
&.reacted {
--bg: var(--reaction-comment-bg);
--bg-hover: var(--reaction-comment-bg);
}
}
&.reaction-readinglist {
&.reacted {
--bg: var(--reaction-save-bg);
--bg-hover: var(--reaction-save-bg);
}
}
.reaction-icon {
--not-reacted-display: inline-block;
--reacted-display: none;
&.not-reacted {
display: var(--not-reacted-display);
}
&.reacted {
display: var(--reacted-display);
}
}
&.reacted {
.reaction-icon {
--not-reacted-display: none;
--reacted-display: inline-block;
}
}
}

View file

@ -7,11 +7,11 @@ class ReactionImage
def path
images = {
"like" => "emoji/emoji-one-heart.png",
"unicorn" => "emoji/emoji-one-unicorn.png",
"like" => "heart-filled.svg",
"unicorn" => "unicorn-filled.svg",
"hands" => "emoji/emoji-one-hands.png",
"thinking" => "emoji/emoji-one-thinking.png",
"readinglist" => "emoji/emoji-one-bookmark.png",
"readinglist" => "save-filled.svg",
"thumbsdown" => "emoji/emoji-one-thumbs-down.png",
"vomit" => "emoji/emoji-one-nausea-face.png"
}.freeze

View file

@ -1,34 +1,45 @@
<%# TODO: change to map of IDs %>
<% actors = siblings.map { |n| n["user"] }.uniq %>
<% reactable_data = notification.json_data["reaction"]["reactable"] %>
<a href="<%= actors.first["path"] %>" class="small-pic-link-wrapper">
<div class="small-pic">
<img src="<%= actors.first["profile_image_90"] %>" alt="link to <%= actors.first["username"] %>'s profile">
</div>
</a>
<div class="content notification-content reaction-content">
<div class="relative shrink-0 self-start">
<% if actors.size == 1 %>
<a href="<%= actors.first["path"] %>"><%= actors.first["name"] %></a>
<% elsif actors.size == 2 %>
<a href="<%= actors.first["path"] %>"><%= actors.first["name"] %></a> and
<a href="<%= actors.last["path"] %>"><%= actors.last["name"] %></a>
<% elsif actors.size > 1 %>
<a href="<%= actors.first["path"] %>"><%= actors.first["name"] %></a> and <%= pluralize(actors.size - 1, "other") %>
<a href="<%= actors.first["path"] %>" class="crayons-avatar crayons-avatar--xl">
<img src="<%= actors.first["profile_image_90"] %>" class="crayons-avatar__image" alt="link to <%= actors.first["username"] %>'s profile" width="48" height="48">
</a>
<% else %>
<a href="<%= actors.first["path"] %>" class="crayons-avatar crayons-avatar--l mr-4">
<img src="<%= actors.first["profile_image_90"] %>" class="crayons-avatar__image" alt="link to <%= actors.first["username"] %>'s profile" width="48" height="48">
</a>
<a href="<%= actors.first["path"] %>" class="crayons-avatar crayons-avatar--l absolute -right-1 -bottom-3 border-solid border-2 border-base-inverted">
<img src="<%= actors.last["profile_image_90"] %>" class="crayons-avatar__image" alt="link to <%= actors.last["username"] %>'s profile" width="48" height="48">
</a>
<% end %>
</div>
<div class="notification__content pt-2">
<span class="inline-block py-1">
<% if actors.size == 1 %>
<a href="<%= actors.first["path"] %>" class="crayons-link fw-bold"><%= actors.first["name"] %></a>
<% elsif actors.size == 2 %>
<a href="<%= actors.first["path"] %>" class="crayons-link fw-bold"><%= actors.first["name"] %></a> and
<a href="<%= actors.last["path"] %>" class="crayons-link fw-bold"><%= actors.last["name"] %></a>
<% elsif actors.size > 1 %>
<a href="<%= actors.first["path"] %>" class="crayons-link fw-bold"><%= actors.first["name"] %></a> and <%= pluralize(actors.size - 1, "other") %>
<% end %>
reacted to
<a href="<%= reactable_data["path"] %>" class="crayons-link fw-bold">
<%# your article/comment or the actual title of the article/comment %>
<%= reactable_data["title"].blank? ? "your #{reactable_data['class']['name'].downcase}" : h(reactable_data["title"]) %>
</a>
with
</span>
<% reaction_categories = siblings.map { |n| n["category"] } %>
<% reaction_categories.each do |cat| %>
<% image_path = ReactionImage.new(cat).path %>
<% if image_path.present? %>
<%= inline_svg_tag(image_path, aria: true, class: "crayons-icon reaction-image mx-1 my-1 reaction-icon--#{cat}", title: cat.to_s.humanize) %>
<% end %>
<% end %>
reacted to
<a href="<%= reactable_data["path"] %>" class="notification-comment-reacted-link">
<%# your article/comment or the actual title of the article/comment %>
<%= reactable_data["title"].blank? ? "your #{reactable_data['class']['name'].downcase}" : h(reactable_data["title"]) %>
</a>
<span class="reaction-images">
with
<% reaction_categories = siblings.map { |n| n["category"] } %>
<% reaction_categories.each do |cat| %>
<% image_path = ReactionImage.new(cat).path %>
<% if image_path.present? %>
<%= image_tag(image_path, class: "reaction-image", alt: cat.to_s.humanize) %>
<% end %>
<% end %>
</span>
</div>

View file

@ -1,59 +1,60 @@
<% if notification.action == "Reaction" %>
<%= render "reaction", notification: notification %>
<% elsif notification.action.include? "Milestone" %>
<%= render "milestone", notification: notification %>
<% else %>
<% json_data = notification.json_data %>
<% if json_data["organization"] %>
<div class="article-organization-headline">
<a class="org-headline-filler" href="<%= json_data["organization"]["path"] %>">
<img alt="<%= json_data["organization"]["name"] %> logo" src="<%= json_data["organization"]["profile_image_90"] %>">
<%= json_data["organization"]["name"] %>
</a>
</div>
<% end %>
<a href="<%= json_data["user"]["path"] %>" class="small-pic-link-wrapper">
<div class="small-pic">
<img src="<%= json_data["user"]["profile_image_90"] %>" alt="link to <%= json_data["user"]["username"] %>'s profile">
</div>
</a>
<div class="content notification-content article-content">
<a href="<%= json_data["user"]["path"] %>">
<%= json_data["user"]["name"] %>
</a>
made a new post<%= ":" unless json_data["organization"] %>
<% if json_data["organization"] %>
under <a href="<%= json_data["organization"]["path"] %>"><%= json_data["organization"]["name"] %></a>:
<% end %>
<div class="crayons-card notification">
<% if notification.action == "Reaction" %>
<%= render "reaction", notification: notification %>
<% elsif notification.action.include? "Milestone" %>
<%= render "milestone", notification: notification %>
<% else %>
<% json_data = notification.json_data %>
<%= render "notifications/shared/profile_pic", json_data: json_data %>
<div>
<small><%= time_ago_in_words json_data["article"]["published_at"] %> ago</small>
</div>
<a href="<%= json_data["article"]["path"] %>">
<div class="notification-new-post">
<div class="notification-new-post-title">
<%= h(json_data["article"]["title"]) %>
</div>
<div class="notification-new-post-tags">
<% json_data["article"]["cached_tag_list_array"].each do |tag| %>
#<%= tag %>
<div class="notification__content">
<header class="mb-4">
<h2 class="fs-base fw-normal">
<a href="<%= json_data["user"]["path"] %>" class="crayons-link fw-bold">
<%= json_data["user"]["name"] %>
</a>
made a new post
<% if json_data["organization"] %>
under <a href="<%= json_data["organization"]["path"] %>" class="crayons-link fw-bold"><%= json_data["organization"]["name"] %></a>
<% end %>
</div>
</div>
</a>
</h2>
<p class="lh-tight"><small class="fs-s color-base-60"><%= time_ago_in_words json_data["article"]["published_at"] %> ago</small></p>
</header>
<% cache "activity-published-article-reactions-#{@last_user_reaction}-#{json_data['article']['updated_at']}-#{json_data['article']['id']}" do %>
<div class="comment-actions">
<button class="reaction-button <%= Reaction.cached_any_reactions_for?(notification.mocked_object("article"), current_user, "like") ? "reacted" : "" %>" data-reactable-id="<%= json_data["article"]["id"] %>" data-category="like" data-reactable-type="Article">
<%= image_tag("favorite-heart-outline-button.svg", alt: "Favorite heart outline button") %>
<img class="reacted-emoji" src="<%= asset_path("emoji/emoji-one-heart.png") %>" alt="Favorite heart button" />
</button>
<button class="reaction-button readinglist-button <%= Reaction.cached_any_reactions_for?(notification.mocked_object("article"), current_user, "readinglist") ? "reacted" : "" %>" data-reactable-id="<%= json_data["article"]["id"] %>" data-category="readinglist" data-reactable-type="Article">
<span class="reaction-button-text">SAVE</span>
<img class="reacted-emoji reaction-button-reacted-emoji" src="<%= asset_path("readinglist-button.png") %>" alt="Save button" />
</button>
</div>
<% end %>
</div>
<% end %>
<article class="notification__preview crayons-card">
<a href="<%= json_data["article"]["path"] %>" class="crayons-link block p-3 pb-4">
<h3 class="notification__preview__title"><%= h(json_data["article"]["title"]) %></h3>
<div class="-ml-1">
<% json_data["article"]["cached_tag_list_array"].each do |tag| %>
<span class="crayons-tag"><span class="crayons-tag__prefix">#</span><%= tag %></span>
<% end %>
</div>
</a>
<% cache "activity-published-article-reactions-#{@last_user_reaction}-#{json_data['article']['updated_at']}-#{json_data['article']['id']}" do %>
<footer class="comment-actions notification__actions">
<button
class="crayons-btn crayons-btn--ghost crayons-btn--icon-left crayons-btn--s reaction-like reaction-button <%= Reaction.cached_any_reactions_for?(notification.mocked_object("article"), current_user, "like") ? "reacted" : "" %>"
data-reactable-id="<%= json_data["article"]["id"] %>"
data-category="like"
data-reactable-type="Article">
<%= inline_svg_tag("small-heart.svg", aria: true, class: "crayons-icon reaction-icon not-reacted", title: "Favorite heart button") %>
<%= inline_svg_tag("small-heart-filled.svg", aria: true, class: "crayons-icon reaction-icon--like reaction-icon reacted", title: "Favorite heart button") %>
<span class="hidden m:inline-block">Like</span>
</button>
<button
class="ml-auto crayons-btn crayons-btn--ghost crayons-btn--icon-right crayons-btn--s reaction-readinglist reaction-button readinglist-button <%= Reaction.cached_any_reactions_for?(notification.mocked_object("article"), current_user, "readinglist") ? "reacted" : "" %>"
data-reactable-id="<%= json_data["article"]["id"] %>"
data-category="readinglist"
data-reactable-type="Article">
<span class="reaction-button-text hidden m:inline-block">Save</span>
<%= inline_svg_tag("small-save.svg", aria: true, class: "crayons-icon reaction-icon not-reacted", title: "Save button") %>
<%= inline_svg_tag("small-save-filled.svg", aria: true, class: "crayons-icon reaction-icon--readinglist reaction-icon reacted", title: "Save button") %>
</button>
</footer>
<% end %>
</article>
</div>
<% end %>
</div>

View file

@ -1,30 +1,20 @@
<% json_data = notification.json_data %>
<div class="content notification-content badge-content">
<div class="crayons-card notification notification--promoted grid gap-4">
<% cache "activity-badge-reward-#{json_data['badge_achievement']['badge_id']}" do %>
<div class="badge-title">
You received the <strong><%= sanitize(json_data["badge_achievement"]["badge"]["title"]) %></strong> badge
<header>
<h3 class="fw-normal fs-2xl">
You received the <strong class="fw-bold"><%= sanitize(json_data["badge_achievement"]["badge"]["title"]) %></strong> badge
</h3>
<p class="fs-l"><%= json_data["badge_achievement"]["badge"]["description"] %></p>
</header>
<div class="crayons-card crayons-card--secondary p-4 w-100 grid gap-2">
<img class="w-100 max-w-50 l:max-w-25 h-auto inline-block mx-auto" src="<%= optimized_image_url(json_data["badge_achievement"]["badge"]["badge_image_url"], width: 250) %>" alt="<%= json_data["badge_achievement"]["badge"]["title"] %>">
<p class="color-base-70"><em><%= json_data["badge_achievement"]["rewarding_context_message"].html_safe %></em></p>
</div>
<p class="badge-description">
<%= json_data["badge_achievement"]["badge"]["description"] %>
</p>
<img class="badge-image" src="<%= optimized_image_url(json_data["badge_achievement"]["badge"]["badge_image_url"], width: 250) %>" alt="<%= json_data["badge_achievement"]["badge"]["title"] %>">
<% end %>
<p class="badge-reward-message">
<em>
<%= json_data["badge_achievement"]["rewarding_context_message"].html_safe %>
</em>
</p>
<a href="<%= json_data["user"]["path"] %>">
<button class="crayons-btn follow-action-button badge-button">
Visit your profile
</button>
</a>
<hr class="minimal-divider" />
<p class="badge-credit-message">
You also get <strong><a href="/credits">5 new credits</a></strong> to use for <strong><a href="/listings">community listings</a></strong><br />
if you have anything you'd like to promote. 🎉
</p>
<p class="badge-credit-message">
<strong><a href="<%= about_listings_url %>">More information about listings<a></strong>
</p>
<p><a href="<%= json_data["user"]["path"] %>" class="crayons-btn w-100 m:w-50">Visit your profile</a></p>
<p class="max-w-75 mx-auto">You also get <a href="/credits" class="crayons-link crayons-link--brand fw-bold">5 new credits</a> to use for <a href="/listings">community listings</a> if you have anything you'd like to promote. 🎉</p>
<p class="fs-s"><a href="<%= about_listings_url %>" class="crayons-link crayons-link--secondary">More information about listings<a></p>
</div>

View file

@ -1,16 +1,16 @@
<% json_data = notification.json_data %>
<% user = User.find_by(id: json_data["user"]["id"]) %>
<% cache "broadcast-html-#{notification.json_data['broadcast']['title']}" do %>
<a href="<%= json_data["user"]["path"] %>" class="small-pic-link-wrapper">
<div class="small-pic">
<img src="<%= Images::Profile.call(user.profile_image_url) %>" alt="link to <%= json_data["user"]["username"] %>'s profile">
</div>
</a>
<div class="content notification-content broadcast-content" id="<%= sanitized_broadcast_id(json_data["broadcast"]["title"]) %>">
<%= json_data["broadcast"]["processed_html"].html_safe %>
<div class="crayons-card p-9 notification notification--promoted">
<% json_data = notification.json_data %>
<% user = User.find_by(id: json_data["user"]["id"]) %>
<% cache "broadcast-html-#{notification.json_data['broadcast']['title']}" do %>
<a href="<%= json_data["user"]["path"] %>" class="crayons-avatar crayons-avatar--3xl shrink-0 mb-6">
<img src="<%= Images::Profile.call(user.profile_image_url) %>" class="crayons-avatar__image" alt="link to <%= json_data["user"]["username"] %>'s profile" width="48" height="48">
</a>
<div class="fs-l broadcast-content" id="<%= sanitized_broadcast_id(json_data["broadcast"]["title"]) %>">
<%= json_data["broadcast"]["processed_html"].html_safe %>
<% if notification.json_data['broadcast']['type_of'] == "Welcome" %>
<div class="opt-out"><a href="<%= user_settings_path(tab: :notifications) %>">Go to your settings to manage your notification settings.</a></div>
<% end %>
</div>
<% end %>
<% if notification.json_data['broadcast']['type_of'] == "Welcome" %>
<p class="fs-base pt-6 color-base-70">Visit <a href="<%= user_settings_path(tab: :notifications) %>">Settings</a> to manage your notifications.</p>
<% end %>
</div>
<% end %>
</div>

View file

@ -1,56 +1,68 @@
<% if notification.action == "Reaction" %>
<%= render "reaction", notification: notification %>
<% else %>
<% json_data = notification.json_data %>
<% cache "activity-profile-pic-#{json_data['user']['id']}-#{json_data['user']['profile_image_90']}" do %>
<a href="<%= json_data["user"]["path"] %>" class="small-pic-link-wrapper">
<div class="small-pic">
<img src="<%= json_data["user"]["profile_image_90"] %>" alt="link to <%= json_data["user"]["username"] %>'s profile">
</div>
</a>
<% end %>
<div class="content notification-content comment-content">
<% if notification.action.blank? %>
<a href="<%= json_data["user"]["path"] %>"><%= json_data["user"]["name"] %></a>
<% if json_data["comment"]["depth"] && json_data["comment"]["depth"] > 0 %>
replied to a thread in
<% else %>
commented on
<% end %>
<a href="<%= json_data["comment"]["commentable"]["path"] %>">
<%= h(json_data["comment"]["commentable"]["title"]) %>
</a>
<% if json_data["comment"]["created_at"] %>
<div>
<small><%= time_ago_in_words json_data["comment"]["created_at"] %> ago</small>
</div>
<% end %>
<%= render "notifications/shared/comment_box", json_data: json_data, notification: notification, context: "default" %>
<% elsif notification.action == "Moderation" %>
<a href="/<%= json_data["comment"]["path"].split("/")[1] %>">@<%= json_data["comment"]["path"].split("/")[1] %></a> just left a comment. Since they are new to the community, could you leave a nice reply to help them feel welcome?
<b>Thank you!</b>
<br /><br />
<em style="font-size: 0.9em">Alternatively, if this comment violates the code of conduct, please downvote/report as appropriate.</em>
<br /><br>
<b>re:
<a href="<%= json_data["comment"]["commentable"]["path"] %>">
<%= h(json_data["comment"]["commentable"]["title"]) %>
</a></b>
<%= render "notifications/shared/comment_box", json_data: json_data, notification: notification, context: "moderation" %>
<br>
<div class="footnote">All negative reactions are 100% private.</div>
<% elsif notification.action == "First" %>
<a href="<%= json_data["user"]["path"] %>"><%= json_data["user"]["name"] %></a>
wrote their first comment on:
<a href="<%= json_data["comment"]["commentable"]["path"] %>">
<%= h(json_data["comment"]["commentable"]["title"]) %>
</a>
<div>
<small><%= time_ago_in_words notification.created_at %> ago</small>
</div>
<%= render "notifications/shared/comment_box", activity: activity, context: "moderation" %>
Give them their first reply! 🎉
<br>
<div class="crayons-card notification">
<% if notification.action == "Reaction" %>
<%= render "reaction", notification: notification %>
<% else %>
<% json_data = notification.json_data %>
<% cache "activity-profile-pic-#{json_data['user']['id']}-#{json_data['user']['profile_image_90']}" do %>
<%= render "notifications/shared/profile_pic", json_data: json_data %>
<% end %>
</div>
<% end %>
<div class="notification__content">
<% if notification.action.blank? %>
<% if json_data["comment"]["created_at"] %>
<header class="mb-4">
<h2 class="fs-base fw-normal">
<a href="<%= json_data["user"]["path"] %>" class="crayons-link fw-bold">
<%= json_data["user"]["name"] %>
</a>
<% if json_data["comment"]["depth"] && json_data["comment"]["depth"] > 0 %>
replied to a thread in
<% else %>
commented on
<% end %>
<a href="<%= json_data["comment"]["commentable"]["path"] %>" class="crayons-link fw-bold">
<%= h(json_data["comment"]["commentable"]["title"]) %>
</a>
</h2>
<p class="lh-tight"><a href="<%= json_data["comment"]["path"] %>" class="crayons-link fs-s crayons-link--secondary"><%= time_ago_in_words json_data["comment"]["created_at"] %> ago</a></p>
</header>
<% end %>
<%= render "notifications/shared/comment_box", json_data: json_data, notification: notification, context: "default" %>
<% elsif notification.action == "Moderation" %>
<header class="mb-4">
<h2 class="fs-base fw-normal">
<a href="/<%= json_data["comment"]["path"].split("/")[1] %>" class="crayons-link fw-bold"><%= json_data["comment"]["path"].split("/")[1] %></a>
just left a comment on
<a href="<%= json_data["comment"]["commentable"]["path"] %>" class="crayons-link fw-bold">
<%= h(json_data["comment"]["commentable"]["title"]) %>
</a>.
</h2>
<p>Since they are new to the community, could you leave a nice reply to help them feel welcome? <strong>Thank you!</strong></p>
</header>
<%= render "notifications/shared/comment_box", json_data: json_data, notification: notification, context: "moderation" %>
<p class="fs-s color-base-60 pt-4">All negative reactions are 100% private. If this comment violates the code of conduct, please downvote/report as inappropriate.</p>
<% elsif notification.action == "First" %>
<header class="mb-4">
<h2 class="fs-base fw-normal">
<a href="<%= json_data["user"]["path"] %>" class="crayons-link fw-bold"><%= json_data["user"]["name"] %></a>
wrote their first comment on
<a href="<%= json_data["comment"]["commentable"]["path"] %>" class="crayons-link fw-bold">
<%= h(json_data["comment"]["commentable"]["title"]) %>
</a>
</h2>
<p class="lh-tight"><small class="fs-s color-base-60"><%= time_ago_in_words notification.created_at %> ago</small></p>
<p>Give them their first reply! 🎉</p>
</header>
<%= render "notifications/shared/comment_box", activity: activity, context: "moderation" %>
<% end %>
</div>
<% end %>
</div>

View file

@ -1,44 +1,36 @@
<% first_notification = notification.json_data["aggregated_siblings"].first %>
<% cache "activity-profile-pic-#{first_notification['id']}-#{first_notification['profile_image_90']}" do %>
<a href="<%= first_notification["path"] %>" class="small-pic-link-wrapper">
<div class="small-pic">
<img src="<%= first_notification["profile_image_90"] %>" alt="link to <%= first_notification["username"] %>'s profile">
</div>
</a>
<% end %>
<div class="content notification-content reaction-content">
<div class="crayons-card notification <% if notification.json_data["aggregated_siblings"].length == 1 %> notification--middle <% else %> flex-col items-center <% end %>">
<% if notification.json_data["aggregated_siblings"].length == 1 %>
<% cache "activity-follow-button-#{first_notification['path']}-#{first_notification['name']}" do %>
<a href="<%= first_notification["path"] %>"><%= first_notification["name"] %></a> followed you!
<%= follow_button(notification.decorate.mocked_object("user"), "follow-back") %>
<% first_notification = notification.json_data["aggregated_siblings"].first %>
<% cache "activity-profile-pic-#{first_notification['id']}-#{first_notification['profile_image_90']}" do %>
<a href="<%= first_notification["path"] %>" class="crayons-avatar <% if notification.json_data["aggregated_siblings"].length == 1 %>crayons-avatar--xl<% else %>crayons-avatar--l<% end %> shrink-0">
<img src="<%= first_notification["profile_image_90"] %>" class="crayons-avatar__image" alt="link to <%= first_notification["username"] %>'s profile" width="48" height="48">
</a>
<% end %>
<% elsif notification.json_data["aggregated_siblings"].length == 2 %>
<% json_data_array = notification["json_data"]["aggregated_siblings"] %>
<div class="follower-pic-row">
<div class="tiny-pic">
<a href="<%= json_data_array.last["path"] %>">
<img src="<%= json_data_array.last["profile_image_90"] %>" alt="link to <%= json_data_array.last["name"] %>'s profile" class="round">
</a>
</div>
</div>
<br>
<div class="notification-message">
<a href="<%= json_data_array.first["path"] %>"><%= json_data_array.first["name"] %></a> and
<a href="<%= json_data_array.second["path"] %>"><%= json_data_array.second["name"] %></a> followed you!
</div>
<% else %>
<div class="follower-pic-row">
<% notification.json_data["aggregated_siblings"][1..10].each do |sibling| %>
<div class="tiny-pic">
<a href="<%= sibling["path"] %>">
<img src="<%= sibling["profile_image_90"] %>" alt="link to <%= sibling["name"] %>'s profile" class="round">
</a>
<div class="notification__content">
<% cache "activity-follow-button-#{first_notification['path']}-#{first_notification['name']}" do %>
<div class="flex justify-between items-center">
<p><a href="<%= first_notification["path"] %>" class="crayons-link fw-bold"><%= first_notification["name"] %></a> followed you!</p>
<%= follow_button(notification.decorate.mocked_object("user"), "follow-back") %>
</div>
<% end %>
</div>
<br>
<a href="<%= first_notification["path"] %>"><%= first_notification["name"] %></a>
and <%= notification.json_data["aggregated_siblings"].size - 1 %> others followed you!
<% else %>
<% json_data_array = notification["json_data"]["aggregated_siblings"] %>
<div class="flex mb-3">
<% notification.json_data["aggregated_siblings"][0..10].each do |sibling| %>
<a href="<%= sibling["path"] %>" class="crayons-avatar crayons-avatar--l shrink-0 mx-1">
<img src="<%= sibling["profile_image_90"] %>" class="crayons-avatar__image" alt="link to <%= sibling["name"] %>'s profile" width="32" height="32">
</a>
<% end %>
</div>
<p>
<% if notification.json_data["aggregated_siblings"].length == 2 %>
<a href="<%= json_data_array.first["path"] %>" class="crayons-link fw-bold"><%= json_data_array.first["name"] %></a> and
<a href="<%= json_data_array.second["path"] %>" class="crayons-link fw-bold"><%= json_data_array.second["name"] %></a> followed you!
<% else %>
<a href="<%= json_data_array.first["path"] %>" class="crayons-link fw-bold"><%= json_data_array.first["name"] %></a>
and <%= notification.json_data["aggregated_siblings"].size - 1 %> others followed you!
<% end %>
</p>
<% end %>
</div>

View file

@ -1,14 +1,13 @@
<% json_data = notification.json_data %>
<% cache "activity-profile-pic-#{json_data['user']['id']}-#{json_data['user']['profile_image_90']}" do %>
<a href="<%= json_data["user"]["path"] %>" class="small-pic-link-wrapper">
<div class="small-pic">
<img src="<%= json_data["user"]["profile_image_90"] %>" alt="link to <%= json_data["user"]["username"] %>'s profile">
</div>
</a>
<% end %>
<div class="crayons-card notification">
<% json_data = notification.json_data %>
<% cache "activity-profile-pic-#{json_data['user']['id']}-#{json_data['user']['profile_image_90']}" do %>
<%= render "notifications/shared/profile_pic", json_data: json_data %>
<% end %>
<%# below links to comment thread %>
<div class="content notification-content comment-content">
<a href="<%= json_data["user"]["path"] %>"><%= json_data["user"]["name"] %></a> mentioned you in a comment
<%= render "notifications/shared/comment_box", json_data: json_data, notification: notification, context: "default" %>
<div class="notification__content">
<h2 class="fs-base fw-normal mb-4">
<a href="<%= json_data["user"]["path"] %>" class="crayons-link fw-bold"><%= json_data["user"]["name"] %></a> mentioned you in a comment
</h2>
<%= render "notifications/shared/comment_box", json_data: json_data, notification: notification, context: "default" %>
</div>
</div>

View file

@ -1,18 +1,16 @@
<% json_data = notification.json_data %>
<div class="content notification-content badge-content">
<div class="badge-title">
<div class="p-6 m:p-8 align-center w-100">
<p class="fs-l m:fs-2xl mb-4">🎉🎉🎉🎉🎉🎉🎉🎉</p>
<h2 class="fw-normal fs-xl m:fs-2xl mb-4">
Your post
<a href="<%= json_data["article"]["path"] %>"><%= h(json_data["article"]["title"]) %></a> passed <%= notification.milestone_count %> <%= notification.milestone_type.pluralize.downcase %>!
</div>
<p class="badge-description milestone-emojis">🎉🎉🎉🎉🎉🎉🎉🎉</p>
<a href="<%= json_data["article"]["path"] %>" class="crayons-link fw-bold"><%= h(json_data["article"]["title"]) %></a> passed <%= notification.milestone_count %> <%= notification.milestone_type.pluralize.downcase %>!
</h2>
<a href="https://giphy.com/gifs/<%= json_data["gif_id"] %>" rel="noopener noreferrer" target="_blank">
<img style="height: <%= RandomGif.get_aspect_ratio(json_data["gif_id"]) * 300 %>px;" class="milestone-gif" src="https://media.giphy.com/media/<%= json_data["gif_id"] %>/giphy-downsized.gif" alt="A random celebratory gif!">
<a href="https://giphy.com/gifs/<%= json_data["gif_id"] %>" rel="noopener noreferrer" class="block my-4" target="_blank">
<img class="radius-default w-100 m:max-w-50 h-auto inline-block" src="https://media.giphy.com/media/<%= json_data["gif_id"] %>/giphy-downsized.gif" alt="A random celebratory gif!">
</a>
<br>
<a href="/dashboard">
<button class="crayons-btn follow-action-button badge-button">
Check your dashboard
</button>
<a href="/dashboard" class="crayons-btn w-100 m:w-50">
Check your dashboard
</a>
</div>

View file

@ -1,27 +1,64 @@
<nav class="notification-nav pt-4">
<nav class="hidden m:block pt-4">
<div>
<% if @organizations.present? %>
<h3 class="crayons-subtitle-3 mb-4 pl-2"><%= @user.name %></h3>
<% end %>
<a class="crayons-link crayons-link--block <%= "crayons-link--current" if params[:filter].blank? %>" href="/notifications">
All
</a>
<a class="crayons-link crayons-link--block <%= "crayons-link--current" if params[:filter].to_s.casecmp("comments").zero? && params[:org_id].blank? %>" href="/notifications/comments">
Comments
</a>
<a class="crayons-link crayons-link--block <%= "crayons-link--current" if params[:filter].to_s.casecmp("posts").zero? && params[:org_id].blank? %>" href="/notifications/posts">
Posts
</a>
</div>
<% if @organizations.present? %>
<h3 class="crayons-subtitle-3 mb-4 pl-2"><%= @user.name %></h3>
<% @organizations.each do |org| %>
<div class="pt-6">
<h3 class="crayons-subtitle-3 mb-4 pl-2"><%= org.name %></h3>
<a class="crayons-link crayons-link--block <%= "crayons-link--current" if params[:filter].to_s.casecmp("org").zero? && params[:org_id].to_i == org.id %>" href="/notifications/org/<%= org.id %>">
All
</a>
<a class="crayons-link crayons-link--block <%= "crayons-link--current" if params[:filter].to_s.casecmp("comments").zero? && params[:org_id].to_i == org.id %>" href="/notifications/comments/<%= org.id %>">
Comments
</a>
</div>
<% end %>
<% end %>
<a class="crayons-link crayons-link--block <%= "crayons-link--current" if params[:filter].blank? %>" href="/notifications">
All
</a>
<a class="crayons-link crayons-link--block <%= "crayons-link--current" if params[:filter].to_s.casecmp("comments").zero? && params[:org_id].blank? %>" href="/notifications/comments">
Comments
</a>
<a class="crayons-link crayons-link--block <%= "crayons-link--current" if params[:filter].to_s.casecmp("posts").zero? && params[:org_id].blank? %>" href="/notifications/posts">
Posts
</a>
</nav>
<% if @organizations.present? %>
<% @organizations.each do |org| %>
<nav class="notification-nav pt-6">
<h3 class="crayons-subtitle-3 mb-4 pl-2"><%= org.name %></h3>
<a class="crayons-link crayons-link--block <%= "crayons-link--current" if params[:filter].to_s.casecmp("org").zero? && params[:org_id].to_i == org.id %>" href="/notifications/org/<%= org.id %>">
All
</a>
<a class="crayons-link crayons-link--block <%= "crayons-link--current" if params[:filter].to_s.casecmp("comments").zero? && params[:org_id].to_i == org.id %>" href="/notifications/comments/<%= org.id %>">
Comments
</a>
</nav>
<nav class="block m:hidden px-4">
<% if @organizations.present? %>
<select id="notifications-filter__select" class="crayons-select mb-2">
<option value="/notifications"><%= @user.name %></option>
<% @organizations.each do |org| %>
<option value="/notifications/org/<%= org.id %>" <%= "selected" if params[:org_id].to_i == org.id %>><%= org.name %></option>
<% end %>
</select>
<% end %>
<% end %>
<div class="crayons-tabs <%= "hidden" if params[:org_id].present? %>">
<a class="crayons-tabs__item <%= "crayons-tabs__item--current" if params[:filter].blank? %>" href="/notifications">
All
</a>
<a class="crayons-tabs__item <%= "crayons-tabs__item--current" if params[:filter].to_s.casecmp("comments").zero? && params[:org_id].blank? %>" href="/notifications/comments">
Comments
</a>
<a class="crayons-tabs__item <%= "crayons-tabs__item--current" if params[:filter].to_s.casecmp("posts").zero? && params[:org_id].blank? %>" href="/notifications/posts">
Posts
</a>
</div>
<% if @organizations.present? %>
<% @organizations.each do |org| %>
<div class="crayons-tabs <%= "hidden" unless params[:org_id].to_i == org.id %>">
<a class="crayons-tabs__item <%= "crayons-tabs__item--current" if params[:filter].to_s.casecmp("org").zero? && params[:org_id].to_i == org.id %>" href="/notifications/org/<%= org.id %>">
All
</a>
<a class="crayons-tabs__item <%= "crayons-tabs__item--current" if params[:filter].to_s.casecmp("comments").zero? && params[:org_id].to_i == org.id %>" href="/notifications/comments/<%= org.id %>">
Comments
</a>
</div>
<% end %>
<% end %>
</nav>

View file

@ -1,38 +0,0 @@
<section class="notifications-filter__dropdown s:flex-col">
<% if @organizations.present? %>
<div class="p-2 s:inline-flex">
<select id="notifications-filter__select" class="crayons-select">
<option value="/notifications"><%= @user.name %></option>
<% @organizations.each do |org| %>
<option value="/notifications/org/<%= org.id %>" <%= "selected" if params[:org_id].to_i == org.id %>><%= org.name %></option>
<% end %>
</select>
</div>
<% end %>
<div class="s:inline-flex">
<nav class="crayons-tabs notifications-filter__tabs <%= "hidden" if params[:org_id].present? %>">
<a class="crayons-tabs__item <%= "crayons-tabs__item--current" if params[:filter].blank? %>" href="/notifications">
All
</a>
<a class="crayons-tabs__item <%= "crayons-tabs__item--current" if params[:filter].to_s.casecmp("comments").zero? && params[:org_id].blank? %>" href="/notifications/comments">
Comments
</a>
<a class="crayons-tabs__item <%= "crayons-tabs__item--current" if params[:filter].to_s.casecmp("posts").zero? && params[:org_id].blank? %>" href="/notifications/posts">
Posts
</a>
</nav>
<% if @organizations.present? %>
<% @organizations.each do |org| %>
<nav class="crayons-tabs notifications-filter__tabs <%= "hidden" unless params[:org_id].to_i == org.id %>">
<a class="crayons-tabs__item <%= "crayons-tabs__item--current" if params[:filter].to_s.casecmp("org").zero? && params[:org_id].to_i == org.id %>" href="/notifications/org/<%= org.id %>">
All
</a>
<a class="crayons-tabs__item <%= "crayons-tabs__item--current" if params[:filter].to_s.casecmp("comments").zero? && params[:org_id].to_i == org.id %>" href="/notifications/comments/<%= org.id %>">
Comments
</a>
</nav>
<% end %>
<% end %>
</div>
</section>

View file

@ -1,20 +1,16 @@
<% @notifications.each do |notification| %>
<div
class="single-article single-article-small-pic single-notification <%= "unseen" unless notification.read? %>"
class="mb-2 spec-notification <%= "unseen" unless notification.read? %>"
data-notification-id="<%= notification.id %>">
<%= render notification.notifiable_type.downcase.to_s, notification: notification %>
</div>
<% rescue => e %>
<% rescue => e %>
<% Honeybadger.notify(e, context: { notification_id: notification.id }) %>
<div class="small-pic">
<img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LnVw15KE--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/31047/af153cd6-9994-4a68-83f4-8ddf3e13f0bf.jpg"
alt="Sloan, the sloth mascot">
</div>
<div class="content notification-content comment-content">
An error occurred! This has been logged and we're tracking it.
<br>
If you see too many of these, please report it to <%= email_link %>!
<div class="align-center p-9 py-10 color-base-80 crayons-card mb-2">
<h2 class="fw-bold fs-l">An error occurred!</h2>
<p class="color-base-60 pt-2">This has been logged and we're tracking it. If you see too many of these, please report it to <%= email_link %>!</p>
</div>
<% end %>

View file

@ -1,26 +1,7 @@
<%# missing cache key %>
<% siblings = notification.json_data["reaction"]["aggregated_siblings"].select { |n| n["created_at"] > 24.hours.ago } %>
<% if siblings.length == 0 %>
<% cache "activity-profile-pic-#{notification.json_data['user']['id']}-#{notification.json_data['user']['profile_image_90']}" do %>
<a href="<%= notification.json_data["user"]["path"] %>" class="small-pic-link-wrapper">
<div class="small-pic">
<img src="<%= notification.json_data["user"]["profile_image_90"] %>" alt="link to <%= notification.json_data["user"]["username"] %> profile">
</div>
</a>
<% end %>
<div class="content notification-content reaction-content">
<a href="<%= notification.json_data["user"]["path"] %>"><strong><%= notification.json_data["user"]["name"] %></strong></a> reacted to
<strong>
<a href="<%= notification.json_data["reaction"]["reactable"]["path"] %>" class="notification-comment-reacted-link">
<%# title is blank when it's a comment with only an image, for example %>
<%= notification.json_data["reaction"]["reactable"]["title"].blank? ? "your #{notification.json_data['reaction']['reactable_type'].downcase}" : sanitize(notification.json_data["reaction"]["reactable"]["title"]) %>
</a>
</strong>
<span class="reaction-images">
<% category = notification.json_data["reaction"]["category"] %>
with <%= image_tag(ReactionImage.new(category).path, class: "reaction-image", alt: "a #{category.humanize}") %>
</span>
</div>
<%= render "single_reaction", notification: notification %>
<% else %>
<%= render "aggregated_reactions", notification: notification, siblings: siblings %>
<% end %>

View file

@ -0,0 +1,18 @@
<div class="flex items-center">
<% cache "activity-profile-pic-#{notification.json_data['user']['id']}-#{notification.json_data['user']['profile_image_90']}" do %>
<%= render "notifications/shared/profile_pic", json_data: notification.json_data %>
<% end %>
<div class="notification__content">
<a href="<%= notification.json_data["user"]["path"] %>" class="crayons-link fw-bold"><%= notification.json_data["user"]["name"] %></a>
reacted to
<a href="<%= notification.json_data["reaction"]["reactable"]["path"] %>" class="crayons-link fw-bold">
<%# title is blank when it's a comment with only an image, for example %>
<%= notification.json_data["reaction"]["reactable"]["title"].blank? ? "your #{notification.json_data['reaction']['reactable_type'].downcase}" : sanitize(notification.json_data["reaction"]["reactable"]["title"]) %>
</a>
with
<span>
<% category = notification.json_data["reaction"]["category"] %>
<%= inline_svg_tag(ReactionImage.new(category).path, class: "crayons-icon reaction-image mx-1 reaction-icon--#{category}", title: category.to_s.humanize) %>
</span>
</div>
</div>

View file

@ -1,28 +1,31 @@
<div class="small-pic">
<img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LnVw15KE--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/31047/af153cd6-9994-4a68-83f4-8ddf3e13f0bf.jpg"
alt="Sloan, the sloth mascot">
</div>
<div class="content notification-content comment-content">
<% data = notification.json_data %>
<% removal = data["adjustment_type"] == "removal" %>
Hey there 👋
<br /><br />
Moderators <%= removal ? "removed" : "added" %> the
<b><a href="/t/<%= data["tag_name"] %>" style="font-weight: 900">#<%= data["tag_name"] %></a></b> tag <%= removal ? "from" : "to" %> your post
<a href="<%= data["article"]["path"] %>"><%= h(data["article"]["title"]) %></a>.
<br /><br />
<%= removal ? "Certain tags have special submission guidelines, and mods need to adjust tags to best fit the community." : "Mods felt this tag represented your article." %>
<br /><br />
<div class="comment-text">
<div style="font-size:0.8em;margin-top: -3px;font-weight: 900;margin-bottom: 5px;">Reason for action</div>
<%= data["reason_for_adjustment"] %>
<div class="crayons-card notification">
<span class="crayons-avatar crayons-avatar--xl shrink-0">
<img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LnVw15KE--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/31047/af153cd6-9994-4a68-83f4-8ddf3e13f0bf.jpg" class="crayons-avatar__image" alt="Sloan, the sloth mascot" width="48" height="48">
</span>
<div class="notification__content">
<% data = notification.json_data %>
<% removal = data["adjustment_type"] == "removal" %>
<h3 class="mb-2 color-base-90">Hey there 👋</h3>
<p class="mb-4">
Moderators <%= removal ? "removed" : "added" %> the
<strong><a href="/t/<%= data["tag_name"] %>">#<%= data["tag_name"] %></a></strong> tag
<%= removal ? "from" : "to" %> your post
<a href="<%= data["article"]["path"] %>"><%= h(data["article"]["title"]) %></a>.
<%= removal ? "Certain tags have special submission guidelines, and mods need to adjust tags to best fit the community." : "Mods felt this tag represented your article." %>
</p>
<div class="crayons-card crayons-card--secondary p-4 mb-4">
<p class="color-base-70">
<strong>Reason for action:</strong>
<em><%= data["reason_for_adjustment"] %></em>
</p>
</div>
<% if removal %>
<p class="mb-2">Check out <a href="/tags">other popular tags</a> which may be more appropriate</p>
<% end %>
<p>
Thanks for being part of <%= community_name %>! If you feel like this mod action was a mistake, feel free to contact
<%= email_link %>. 🤗
</p>
</div>
<br />
<% if removal %>
Check out <a href="/tags">other popular tags</a> which may be more appropriate
<% end %>
<br><br />
Thanks for being part of <%= community_name %>! If you feel like this mod action was a mistake, feel free to contact
<%= email_link %>. 🤗
<br /><br />
</div>

View file

@ -40,26 +40,28 @@
</script>
<% if user_signed_in? %>
<div class="home" id="notifications-container">
<div class="side-bar">
<header class="crayons-layout crayons-layout--limited-l crayons-layout--1-col p-4 flex items-center justify-between">
<h1 class="crayons-title">Notifications</h1>
<a href="<%= user_settings_path(tab: :notifications) %>" class="crayons-btn crayons-btn--ghost">Settings</a>
</header>
<div class="crayons-layout crayons-layout--limited-l crayons-layout--2-cols pt-0" id="notifications-container">
<div class="crayons-layout__sidebar-left">
<%= render "notifications/nav_menu" %>
</div>
<div class="articles-list" id="articles-list">
<%= render "notifications/nav_menu_filter" %>
<%= render "notifications_list", params: params %>
</div>
<main class="crayons-layout__content">
<div id="articles-list">
<%= render "notifications_list", params: params %>
</div>
<%# new or less active users that don't have a page worth of notifications
won't be shown the "load more" button %>
<% if @notifications.size >= @initial_page_size %>
<div class="load-more-wrapper">
<button id="load-more-button" type="button" class="crayons-btn crayons-btn--secondary">
<%# new or less active users that don't have a page worth of notifications
won't be shown the "load more" button %>
<% if @notifications.size >= @initial_page_size %>
<button id="load-more-button" type="button" class="crayons-btn crayons-btn--secondary crayons-btn--l my-6 w-100">
Load More
</button>
</div>
<% end %>
<div class="side-bar sidebar-additional"></div>
<% end %>
</main>
</div>
<%= render "articles/fitvids" %>
<% else %>

View file

@ -1,66 +1,89 @@
<% cache "comment-box-#{@last_user_reaction}-#{@last_user_comment}-#{json_data['comment']['updated_at']}-#{json_data['comment']['id']}" do %>
<% if json_data["comment"]["commentable"] %>
<div class="comment-text">
<% if json_data["comment"]["depth"] && json_data["comment"]["depth"] > 0 %>
<a href="<%= json_data["comment"]["ancestors"].last["path"] %>" class="comment-text-header">
re: <%= json_data["comment"]["ancestors"].last["title"] %>
<% if json_data["comment"]["depth"] && json_data["comment"]["depth"] > 0 %>
<h3>
<a href="<%= json_data["comment"]["ancestors"].last["path"] %>" class="crayons-link notification__reply-title">
<span class="fw-normal opacity-50">Re: </span><%= json_data["comment"]["ancestors"].last["title"] %>
</a>
<% end %>
<a href="<%= json_data["comment"]["path"] %>" class="comment-link-wrapper"></a>
<%= json_data["comment"]["processed_html"].html_safe %>
</div>
<div class="comment-actions">
<button class="reaction-button <%= Reaction.cached_any_reactions_for?(notification.mocked_object("comment"), current_user, "like") ? "reacted" : "" %>" data-reactable-id="<%= json_data["comment"]["id"] %>" data-category="like" data-reactable-type="Comment" title="heart">
<%= image_tag("favorite-heart-outline-button.svg", alt: "Favorite heart outline button") %>
<img class="reacted-emoji" src="<%= asset_path("emoji/emoji-one-heart.png") %>" alt="Favorite heart button" />
</button>
<% if context == "moderation" && current_user.has_role?(:trusted) %>
<button
class="reaction-button <%= Reaction.cached_any_reactions_for?(notification.mocked_object("comment"), current_user, "thumbsdown") ? "reacted" : "" %>"
data-reactable-id="<%= json_data["comment"]["id"] %>"
data-category="thumbsdown"
data-reactable-type="Comment"
title="thumbsdown">
<%= image_tag("emoji/emoji-one-thumbs-down-gray.png", alt: "Thumbs down emoji") %>
<img class="reacted-emoji" src="<%= asset_path("emoji/emoji-one-thumbs-down.png") %>" alt="Thumbs down emoji">
</button>
<button
class="reaction-button <%= Reaction.cached_any_reactions_for?(notification.mocked_object("comment"), current_user, "vomit") ? "reacted" : "" %>"
data-reactable-id="<%= json_data["comment"]["id"] %>"
data-category="vomit"
data-reactable-type="Comment"
title="vomit">
<%= image_tag("emoji/emoji-one-nausea-face-gray.png", alt: "Nausea face emoji") %>
<img class="reacted-emoji" src="<%= asset_path("emoji/emoji-one-nausea-face.png") %>" alt="Nausea face emoji">
</button>
<% end %>
<% cache "comment-box-comment-reply-#{@last_user_comment}-#{json_data['comment']['updated_at']}-#{json_data['comment']['id']}" do %>
<% reply = Comment.select(:id, :user_id, :ancestry).find_by(id: json_data["comment"]["id"])&.children&.find_by(user_id: current_user.id) %>
<% if reply %>
<a class="toggle-reply-form already-replied-link" href="<%= reply.path %>">
Replied
</a>
<% else %>
<a class="toggle-reply-form" data-reactable-id="<%= json_data["comment"]["id"] %>" href="#<%= json_data["comment"]["path"] %>">
Reply
</a>
<% end %>
</div>
<% @comment = Comment.new %>
<%= form_for(@comment,
authenticity_token: false,
html: { id: "comment-form-for-#{json_data['comment']['id']}", onsubmit: "handleCommentSubmit.bind(this)(event)", onkeydown: "handleKeyDown(event)" }) do |f| %>
<%= f.hidden_field :commentable_id, value: json_data["comment"]["commentable"]["id"] %>
<%= f.hidden_field :commentable_type, value: json_data["comment"]["commentable"]["class"]["name"] %>
</h3>
<% end %>
<div class="crayons-card notification__preview relative">
<div class="text-styles text-styles--tertiary p-3 py-2">
<%= json_data["comment"]["processed_html"].html_safe %>
</div>
<%= f.hidden_field :parent_id, value: json_data["comment"]["id"] %>
<div class="field" id="textarea-wrapper">
<%= f.text_area :body_markdown, id: "comment-textarea-for-#{json_data['comment']['id']}" %>
</div>
<div class="actions" id="submit-wrapper">
<%= f.submit "Submit", id: "submit-button", class: "comment-action-button", onclick: "validateField(event)" %>
</div>
<% end %>
<% if context == "moderation" && current_user.has_role?(:trusted) %>
<div class="crayons-card crayons-card--secondary crayons-card--elevated notification__mod-controls">
<button
class="crayons-btn crayons-btn--icon crayons-btn--icon-rounded crayons-btn--ghost inline-flex crayons-btn--s reaction-button <%= Reaction.cached_any_reactions_for?(notification.mocked_object("comment"), current_user, "thumbsdown") ? "reacted" : "" %>"
data-reactable-id="<%= json_data["comment"]["id"] %>"
data-category="thumbsdown"
data-reactable-type="Comment"
title="thumbsdown">
<%= image_tag("emoji/emoji-one-thumbs-down-gray.png", alt: "Thumbs down emoji", width: 24, height: 24, class: "reaction-icon not-reacted") %>
<%= image_tag("emoji/emoji-one-thumbs-down.png", alt: "Thumbs down emoji", width: 24, height: 24, class: "reaction-icon reacted") %>
</button>
<button
class="crayons-btn crayons-btn--icon crayons-btn--icon-rounded crayons-btn--ghost inline-flex crayons-btn--s reaction-button <%= Reaction.cached_any_reactions_for?(notification.mocked_object("comment"), current_user, "vomit") ? "reacted" : "" %>"
data-reactable-id="<%= json_data["comment"]["id"] %>"
data-category="vomit"
data-reactable-type="Comment"
title="vomit">
<%= image_tag("emoji/emoji-one-nausea-face-gray.png", alt: "Nausea face emoji", width: 24, height: 24, class: "reaction-icon not-reacted") %>
<%= image_tag("emoji/emoji-one-nausea-face.png", alt: "Nausea face emoji", width: 24, height: 24, class: "reaction-icon reacted") %>
</button>
</div>
<% end %>
<footer class="comment-actions">
<div class="notification__actions">
<button
class="crayons-btn crayons-btn--ghost crayons-btn--icon-left crayons-btn--s mr-1 reaction-like inline-flex reaction-button <%= Reaction.cached_any_reactions_for?(notification.mocked_object("comment"), current_user, "like") ? "reacted" : "" %>"
data-reactable-id="<%= json_data["comment"]["id"] %>"
data-category="like"
data-reactable-type="Comment"
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="hidden m:inline-block">Like</span>
</button>
<% cache "comment-box-comment-reply-#{@last_user_comment}-#{json_data['comment']['updated_at']}-#{json_data['comment']['id']}" do %>
<% reply = Comment.select(:id, :user_id, :ancestry).find_by(id: json_data["comment"]["id"])&.children&.find_by(user_id: current_user.id) %>
<% if reply %>
<a class="crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon-left mr-1 inline-flex reaction-comment reacted" href="<%= reply.path %>">
<%= inline_svg_tag("small-comment-filled.svg", aria: true, class: "crayons-icon reaction-icon--comment reaction-icon reacted", title: "Comment button") %>
<span class="hidden m:inline-block">Replied</span>
</a>
<% else %>
<a class="crayons-btn crayons-btn--ghost crayons-btn--s crayons-btn--icon-left toggle-reply-form mr-1 inline-flex" data-reactable-id="<%= json_data["comment"]["id"] %>" href="#<%= json_data["comment"]["path"] %>">
<%= inline_svg_tag("small-comment.svg", aria: true, class: "crayons-icon reaction-icon not-reacted", title: "Comment button") %>
<%= inline_svg_tag("small-comment-filled.svg", aria: true, class: "crayons-icon reaction-icon--comment reaction-icon reacted", title: "Comment button") %>
<span class="hidden m:inline-block">Reply</span>
</a>
<% end %>
<% end %>
<a href="<%= json_data["comment"]["path"] %>" class="crayons-btn crayons-btn--ghost crayons-btn--icon-left crayons-btn--s inline-flex">
<%= inline_svg_tag("small-link.svg", aria: true, class: "crayons-icon", title: "Comment button") %><span class="hidden m:inline-block">View</span>
</a>
</div>
<% cache "comment-box-comment-reply-#{@last_user_comment}-#{json_data['comment']['updated_at']}-#{json_data['comment']['id']}" do %>
<% @comment = Comment.new %>
<%= form_for(@comment,
authenticity_token: false,
html: { id: "comment-form-for-#{json_data['comment']['id']}", onsubmit: "handleCommentSubmit.bind(this)(event)", onkeydown: "handleKeyDown(event)", class: "p-2 pb-1 pt-3 hidden" }) do |f| %>
<%= f.hidden_field :commentable_id, value: json_data["comment"]["commentable"]["id"] %>
<%= 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..." %>
<div class="actions">
<button type="submit" class="crayons-btn comment-action-button" onclick="validateField(event)">Submit</button>
</div>
<% end %>
<% end %>
</footer>
</div>
<% end %>
<% end %>

View file

@ -0,0 +1,10 @@
<div class="relative shrink-0 self-start">
<% if json_data["organization"] %>
<a class="crayons-logo crayons-logo--xl" href="<%= json_data["organization"]["path"] %>">
<img alt="<%= json_data["organization"]["name"] %> logo" class="crayons-logo__image" src="<%= json_data["organization"]["profile_image_90"] %>" width="48" height="48">
</a>
<% end %>
<a href="<%= json_data["user"]["path"] %>" class="crayons-avatar <% if json_data["organization"] %> crayons-avatar--l absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted <% else %> crayons-avatar--xl <% end %>">
<img src="<%= json_data["user"]["profile_image_90"] %>" class="crayons-avatar__image" alt="link to <%= json_data["user"]["username"] %>'s profile" width="48" height="48">
</a>
</div>

View file

@ -485,7 +485,6 @@ ActiveRecord::Schema.define(version: 2020_10_19_012200) do
t.datetime "updated_at", null: false
t.bigint "user_id"
t.datetime "verified_at"
t.index ["user_id"], name: "index_email_authorizations_on_user_id"
end
create_table "events", force: :cascade do |t|
@ -1266,7 +1265,7 @@ ActiveRecord::Schema.define(version: 2020_10_19_012200) do
t.datetime "last_moderation_notification", default: "2017-01-01 05:00:00"
t.datetime "last_notification_activity"
t.string "last_onboarding_page"
t.datetime "last_reacted_at"
t.datetime "last_reacted_at", default: "2017-01-01 05:00:00"
t.datetime "last_sign_in_at"
t.inet "last_sign_in_ip"
t.string "linkedin_url"

View file

@ -2,6 +2,6 @@ require "rails_helper"
RSpec.describe ReactionImage, type: :labor do
it "returns a category image" do
expect(described_class.new("unicorn").path).to eq("emoji/emoji-one-unicorn.png")
expect(described_class.new("unicorn").path).to eq("unicorn-filled.svg")
end
end

View file

@ -506,7 +506,8 @@ RSpec.describe "NotificationsIndex", type: :request do
end
it "contextualize comment title properly" do
expect(response.body).to include CGI.escapeHTML("re: #{comment.title}")
expect(response.body).to include CGI.escapeHTML("Re")
expect(response.body).to include CGI.escapeHTML(comment.title.to_s)
end
end
@ -710,7 +711,7 @@ RSpec.describe "NotificationsIndex", type: :request do
end
it "renders the proper message" do
expect(response.body).to include "made a new post:"
expect(response.body).to include "made a new post"
end
it "renders the article's path" do
@ -751,7 +752,7 @@ RSpec.describe "NotificationsIndex", type: :request do
it "can view other people's notifications" do
get "/notifications?username=#{user2.username}"
expect(response.body).to include "made a new post:"
expect(response.body).to include "made a new post"
end
end

View file

@ -35,10 +35,10 @@ RSpec.describe "Notifications page", type: :system, js: true do
visit "/notifications"
expect(page).to have_css("div.single-notification")
expect(page).to have_css("div.spec-notification")
click_button("heart")
expect(page).to have_css("img.reacted-emoji")
expect(page).to have_css(".reacted")
click_link("Reply")
@ -49,7 +49,7 @@ RSpec.describe "Notifications page", type: :system, js: true do
follow = leslie.follow(alex)
Notification.send_new_follower_notification_without_delay(follow, is_read: true)
visit "/notifications"
expect(page).to have_css("div.single-notification")
expect(page).to have_css("div.spec-notification")
click_button("Follow back")
expect(page).to have_text("Following")
end
@ -64,9 +64,9 @@ RSpec.describe "Notifications page", type: :system, js: true do
def interact_with_each_emojis
%w[heart thumbsdown vomit].each do |emoji|
click_button(emoji)
expect(page).to have_css("img.reacted-emoji")
expect(page).to have_css(".reacted")
click_button(emoji)
expect(page).not_to have_css("img.reacted-emoji")
expect(page).not_to have_css(".reacted")
end
end
@ -77,7 +77,7 @@ RSpec.describe "Notifications page", type: :system, js: true do
sidekiq_perform_enqueued_jobs
visit "/notifications"
expect(page).to have_css("div.single-notification")
expect(page).to have_css("div.spec-notification")
interact_with_each_emojis
click_link("Reply")