[deploy] Article Design update (#8234)

* flare tag line height

* .

* init

* widgets

* widgets lists

* new tabs on home

* instantclick

* .

* rethinking css

* .

* .

* empty space

* init

* campaign widget

* .

* merge

* .

* update layout

* fix sidebars on home page

* .

* fix onboarding x

* test

* spec

* test

* toolbar fix

* more

* test

* better handling ads

* .

* spec

* card border

* .

* .

* actions bar

* cleanup

* animation

* test

* button width

* .

* better responsiveness and author boxes

* meta info

* padding

* better animation

* optimize videos

* fixes

* spec

* .

* codeblocks in comments

* whoops

* Use .present? correctly as it preloads items

* sticky nav

* Update app/views/articles/_sticky_nav.html.erb

I don't know what I'm doing but @benhalpern says so! e8c0f337a5 (r440248874)

Co-authored-by: Ben Halpern <bendhalpern@gmail.com>

* Update app/views/articles/show.html.erb

I don't know what I'm doing but @benhalpern says so! e8c0f337a5 (r440247802)

Co-authored-by: Ben Halpern <bendhalpern@gmail.com>

* little fixes

* Update app/assets/stylesheets/article-show.scss

Co-authored-by: Ben Halpern <bendhalpern@gmail.com>

* pawel updating ruby code......

* actually better merge

* semantic updates

* .

Co-authored-by: rhymes <rhymesete@gmail.com>
Co-authored-by: Ben Halpern <bendhalpern@gmail.com>
This commit is contained in:
ludwiczakpawel 2020-06-17 15:57:57 +02:00 committed by GitHub
parent 17a9335680
commit 16f4d7d46a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 870 additions and 1311 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 3h4a8 8 0 010 16v3.5c-5-2-12-5-12-11.5a8 8 0 018-8zm2 14h2a6 6 0 000-12h-4a6 6 0 00-6 6c0 3.61 2.462 5.966 8 8.48V17z"/>
</svg>

After

Width:  |  Height:  |  Size: 229 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="M2.821 12.794a6.5 6.5 0 017.413-10.24h-.002L5.99 6.798l1.414 1.414 4.242-4.242a6.5 6.5 0 019.193 9.192L12 22l-9.192-9.192.013-.014z"/>
</svg>

After

Width:  |  Height:  |  Size: 239 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="M21.179 12.794l.013.014L12 22l-9.192-9.192.013-.014A6.5 6.5 0 0112 3.64a6.5 6.5 0 019.179 9.154zM4.575 5.383a4.5 4.5 0 000 6.364L12 19.172l7.425-7.425a4.5 4.5 0 10-6.364-6.364L8.818 9.626 7.404 8.21l3.162-3.162a4.5 4.5 0 00-5.99.334l-.001.001z"/>
</svg>

After

Width:  |  Height:  |  Size: 351 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 2h14a1 1 0 011 1v19.143a.5.5 0 01-.766.424L12 18.03l-7.234 4.536A.5.5 0 014 22.143V3a1 1 0 011-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 208 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 2h14a1 1 0 011 1v19.143a.5.5 0 01-.766.424L12 18.03l-7.234 4.536A.5.5 0 014 22.143V3a1 1 0 011-1zm13 2H6v15.432l6-3.761 6 3.761V4z"/>
</svg>

After

Width:  |  Height:  |  Size: 241 B

View file

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 44 44" width="24" height="24">
<g class="nc-icon-wrapper">
<path fill="#F4900C" d="M39 23a16.96 16.96 0 00-1.04-5.868c-.46 5.389-3.333 8.157-6.335 6.868-2.812-1.208-.917-5.917-.777-8.164.236-3.809-.012-8.169-6.931-11.794 2.875 5.5.333 8.917-2.333 9.125-2.958.231-5.667-2.542-4.667-7.042-3.238 2.386-3.332 6.402-2.333 9 1.042 2.708-.042 4.958-2.583 5.208-2.84.28-4.418-3.041-2.963-8.333A16.936 16.936 0 005 23c0 9.389 7.611 17 17 17s17-7.611 17-17z"/>
<path fill="#FFCC4D" d="M32.394 27.999c.148 3.084-2.561 4.293-4.019 3.709-2.106-.843-1.541-2.291-2.083-5.291s-2.625-5.083-5.708-6c2.25 6.333-1.247 8.667-3.08 9.084-1.872.426-3.753-.001-3.968-4.007A11.964 11.964 0 0010 34c0 .368.023.73.055 1.09C13.125 38.124 17.342 40 22 40s8.875-1.876 11.945-4.91c.032-.36.055-.722.055-1.09 0-2.187-.584-4.236-1.606-6.001z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 900 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.645 8.013c.013-.265-.261-.323-.4-.183-1.16 1.17-1.822 3.865-.344 7.32.294.961 1.938 3.19.84 6.131l-.003.006c-.094.255.206.404.366.263 1.395-1.226 1.933-3.593 1.1-6.375-.488-1.657-1.955-4.226-1.559-7.162zm-3.22 2.738c.05-.137-.124-.417-.326-.225-.939.893-1.316 2.863-.976 4.605.547 2.878 2.374 3.526 2.066 6.629-.028.102.176.38.348.154 1.546-2.033.409-4.453-.241-6.006-1.005-2.386-1.087-4.118-.871-5.157zM22.2 3.543l-8.579 3.68c-.332-.343-.615-.63-.76-.773-.527-.517.313-4.224-.409-4.439-.933-.277-5.042 4.624-4.696 7.953.224 2.735 2.193 4.89 1.72 8.412 3.446-.644 4.841 1.697 5.83 2.45 1.752 1.335 5.155-.551 3.807-3.582-.193-.435-2.05-4.732-2.931-6.775l6.619-5.94c.486-.44-.003-1.242-.601-.986zm-9.418 9.535a.828.828 0 01-.74-.9.825.825 0 01.81-.76c.479 0 .85.42.81.903a.824.824 0 01-.88.757z"/>
</svg>

After

Width:  |  Height:  |  Size: 904 B

View file

@ -0,0 +1,4 @@
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
<path d="M5.645 8.013c.013-.265-.261-.323-.4-.183-1.16 1.17-1.822 3.865-.344 7.32.294.961 1.938 3.19.84 6.131l-.003.006c-.094.255.206.404.366.263 1.395-1.226 1.933-3.593 1.1-6.375-.488-1.657-1.955-4.226-1.559-7.162zm-3.22 2.738c.05-.137-.124-.417-.326-.225-.939.893-1.316 2.863-.976 4.605.547 2.878 2.374 3.526 2.066 6.629-.028.102.176.38.348.154 1.546-2.033.409-4.453-.241-6.006-1.005-2.386-1.087-4.118-.871-5.157z" fill="#08090A"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.622 7.223l8.579-3.68c.598-.256 1.087.547.6.985l-6.618 5.941c.881 2.043 2.738 6.34 2.931 6.775 1.348 3.031-2.055 4.918-3.807 3.583a7.027 7.027 0 01-.623-.574c-.974-.965-2.419-2.398-5.207-1.877.284-2.115-.313-3.737-.883-5.288-.38-1.032-.747-2.032-.837-3.124-.346-3.329 3.763-8.23 4.696-7.953.386.115.326 1.229.266 2.319-.051.948-.102 1.88.143 2.12.145.142.428.43.76.773zM11.5 16.5l2.5.5 2.5 2 1-.5-2-4.5-1.5-4-1.5-1-1-1-1-1.5L10 8l-.5 1.5 1 2.5 1 4.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 1,019 B

View file

@ -145,23 +145,11 @@ function requestReactionCounts(articleId) {
ajaxReq.send();
}
function jumpToComments() {
document.getElementById('jump-to-comments').onclick = (e) => {
e.preventDefault();
document.getElementById('comments').scrollIntoView({
behavior: 'instant',
block: 'start',
});
};
}
function initializeArticleReactions() {
setCollectionFunctionality();
setTimeout(() => {
var reactionButts = document.getElementsByClassName(
'article-reaction-butt',
);
var reactionButts = document.getElementsByClassName('crayons-reaction');
// we wait for the article to appear,
// we also check that reaction buttons are there as draft articles don't have them
@ -176,9 +164,5 @@ function initializeArticleReactions() {
};
}
}
if (document.getElementById('jump-to-comments')) {
jumpToComments();
}
}, 3);
}

View file

@ -42,16 +42,16 @@ function addRelevantButtonsToArticle(user) {
if (articleContainer) {
if (parseInt(articleContainer.dataset.authorId, 10) === user.id) {
let actions = [
`<a href="${articleContainer.dataset.path}/edit" rel="nofollow">EDIT</a>`,
`<a class="crayons-btn crayons-btn--s crayons-btn--secondary ml-1" href="${articleContainer.dataset.path}/edit" rel="nofollow">Edit</a>`,
];
if (JSON.parse(articleContainer.dataset.published) === true) {
actions.push(
`<a href="${articleContainer.dataset.path}/manage" rel="nofollow">MANAGE</a>`,
`<a class="crayons-btn crayons-btn--s crayons-btn--secondary ml-1" href="${articleContainer.dataset.path}/manage" rel="nofollow">Manage</a>`,
);
}
if (user.pro) {
actions.push(
`<a href="${articleContainer.dataset.path}/stats" rel="nofollow">STATS</a>`,
`<a class="crayons-btn crayons-btn--s crayons-btn--secondary ml-1" href="${articleContainer.dataset.path}/stats" rel="nofollow">Stats</a>`,
);
}
document.getElementById('action-space').innerHTML = actions.join('');
@ -71,17 +71,17 @@ function addRelevantButtonsToComments(user) {
butt.innerHTML =
'<a href="' +
butt.dataset.path +
'" rel="nofollow" style="color:#0a0a0a;" data-no-instant>Settings</a>';
butt.style.display = 'inline-block';
'" rel="nofollow" class="crayons-link crayons-link--block" data-no-instant>Settings</a>';
butt.classList.remove('hidden');
butt.classList.add('block');
}
if (
action === 'hide-button' &&
parseInt(commentableUserId, 10) === user.id
) {
butt.style.display = 'inline-block';
butt.classList.remove('hidden');
butt.classList.add('block');
}
}
@ -91,10 +91,13 @@ function addRelevantButtonsToComments(user) {
let butt = modButts[i];
if (butt.classList.contains('mod-actions-comment-button')) {
butt.innerHTML =
'<a href="' + butt.dataset.path + '" rel="nofollow">Moderate</a>';
'<a href="' +
butt.dataset.path +
'" rel="nofollow" class="crayons-link crayons-link--block">Moderate</a>';
}
butt.className = 'mod-actions';
butt.style.display = 'inline-block';
butt.classList.remove('hidden');
butt.classList.add('block');
}
}
}

View file

@ -1,25 +1,24 @@
'use strict';
function initializeCommentDropdown() {
const announcer = document.getElementById('article-copy-link-announcer');
function isClipboardSupported() {
return (
typeof navigator.clipboard !== "undefined" &&
navigator.clipboard !== null
typeof navigator.clipboard !== 'undefined' && navigator.clipboard !== null
);
}
function isNativeAndroidDevice() {
return (
navigator.userAgent === 'DEV-Native-android' &&
typeof AndroidBridge !== "undefined" &&
typeof AndroidBridge !== 'undefined' &&
AndroidBridge !== null
);
}
function removeClass(className) {
return element => element.classList.remove(className);
return (element) => element.classList.remove(className);
}
function getAllByClassName(className) {
@ -54,7 +53,8 @@ function initializeCommentDropdown() {
AndroidBridge.copyToClipboard(inputValue);
showAnnouncer();
} else if (isClipboardSupported()) {
navigator.clipboard.writeText(inputValue)
navigator.clipboard
.writeText(inputValue)
.then(() => {
showAnnouncer();
})
@ -72,7 +72,7 @@ function initializeCommentDropdown() {
event.target.matches('.dropbtn') ||
event.target.matches('clipboard-copy') ||
event.target.matches('clipboard-copy input') ||
event.target.matches('clipboard-copy img') ||
event.target.matches('clipboard-copy svg') ||
event.target.parentElement.classList.contains('dropdown-link-row')
);
}
@ -94,7 +94,7 @@ function initializeCommentDropdown() {
}
function removeAllShowing() {
getAllByClassName('showing').forEach(removeClass('showing'));
getAllByClassName('crayons-dropdown').forEach(removeClass('block'));
}
function outsideClickListener(event) {
@ -108,16 +108,16 @@ function initializeCommentDropdown() {
function dropdownFunction(e) {
var button = e.target.parentElement;
var dropdownContent = button.parentElement.getElementsByClassName(
'dropdown-content',
'crayons-dropdown',
)[0];
if (dropdownContent.classList.contains('showing')) {
dropdownContent.classList.remove('showing');
if (dropdownContent.classList.contains('block')) {
dropdownContent.classList.remove('block');
removeClickListener();
removeCopyListener();
hideAnnouncer();
} else {
removeAllShowing();
dropdownContent.classList.add('showing');
dropdownContent.classList.add('block');
const clipboardCopyElement = document.getElementsByTagName(
'clipboard-copy',
)[0];

View file

@ -54,14 +54,14 @@ function buildCommentHTML(comment) {
<%= image_tag("three-dots.svg", class: "dropdown-icon", alt: "Toggle dropdown menu") %>\
</button>\
<div class="dropdown">\
<div class="dropdown-content">\
<a href="'+comment.url+'">\
<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+'/settings">\
<a href="'+comment.url+'/settings" class="crayons-link crayons-link--block">\
Settings\
</a>\
<a href="/report-abuse?url=<%= URL.url %>'+comment.url+'">Report Abuse</a>\
<a href="/report-abuse?url=<%= URL.url %>'+comment.url+'" class="crayons-link crayons-link--block">Report Abuse</a>\
</div>\
</div>\
</div>\

View file

@ -866,498 +866,6 @@ article {
}
}
.article-actions {
text-align: center;
padding: 5px 0 12px;
position: fixed;
bottom: 0;
z-index: 22;
width: 100%;
@include themeable(background, theme-container-background, $tan);
@include themeable(box-shadow, theme-container-box-shadow, $bold-shadow);
@media screen and (min-width: 950px) {
border-radius: 3px 3px 0 0;
}
.dropdown-content {
clipboard-copy {
display: flex;
flex-flow: row wrap;
position: relative;
width: calc(100% - 24px);
margin-left: 12px;
cursor: pointer;
#article-copy-link-input {
border-radius: 3px;
border: 1px dashed black;
flex: 1 1 auto;
font-size: 1em;
margin: 10px auto;
padding: 4px 6px;
width: auto;
}
img {
flex: 1 0 24px;
max-width: 24px;
margin-left: 5px;
@include themeable(filter, theme-social-icon-invert, invert(0));
}
input {
cursor: pointer;
}
#article-copy-link-announcer {
flex: 1 0 100%;
color: $bold-blue;
position: absolute;
bottom: -8px;
padding-left: 0px;
font-size: 12px;
text-align: left;
&[hidden] {
display: none;
}
}
}
}
@media screen and (min-width: 880px) {
width: 880px;
}
@media screen and (min-width: 1365px) {
margin-left: -1px;
margin-right: -1px;
width: calc(55px + 1.1vw);
top: 0%;
padding: calc(11px + 6%) 0px;
bottom: 5%;
left: calc(50% - 672px);
background: transparent;
border: 0;
box-shadow: none;
transition: opacity 0.25s;
padding-right: 2px;
.article-share-action-block {
width: 100% !important;
}
button,
a {
display: block !important;
width: 100% !important;
padding: 7px 0px !important;
margin-left: 0px !important;
margin-right: 0px !important;
border: 0px !important;
transition-delay: 0.1s;
&.user-animated {
img {
animation: image-reaction-animation 0.3s !important;
}
}
&:focus-visible {
outline: 0;
box-shadow: 0px 0px 4px $medium-gray !important;
}
}
a {
margin-top: 5px !important;
font-size: 0.67em !important;
padding: 10px 0px 9px !important;
&.article-actions-comments-count {
padding: 12px 0 !important;
}
}
.dropdown-content {
left: 80px !important;
bottom: 0px !important;
@media screen and (min-width: 1365px) {
bottom: -185px !important;
}
a {
background: transparent !important;
padding-left: 10px !important;
}
}
}
@media screen and (min-width: 1439px) {
width: calc(90px + 1.1vw);
left: calc(50% - 711px);
a {
font-size: 0.7em !important;
}
button {
padding: 9px 0px !important;
}
.dropdown-content {
left: 100px !important;
}
}
@media screen and (min-width: 1530px) {
width: 156px;
left: calc(50% - 750px);
button,
a {
width: 140px !important;
}
a {
font-size: 0.79em !important;
}
.dropdown-content {
left: 150px !important;
}
button {
padding: 12px 0px !important;
}
}
button {
background: transparent;
margin: 0px calc(0.22vw + 2px);
padding: 2px calc(0.88vw + 6px);
padding-right: calc(0.88vw + 10px);
border: 0px;
font-weight: bold;
font-stretch: condensed;
img {
height: 23px;
width: 23px;
transition: -webkit-filter 0.2s, opacity 0.2s;
padding: 4px;
border-radius: 100px;
transition: box-shadow 0.18s;
background: var(--card-bg);
@media screen and (min-width: 500px) {
height: 26px;
width: 26px;
}
@media screen and (min-width: 1365px) {
height: 19px;
width: 19px;
}
@media screen and (min-width: 1439px) {
height: 23px;
width: 23px;
}
@media screen and (min-width: 1530px) {
height: 28px;
width: 28px;
padding: 7px;
}
}
&:hover {
img {
box-shadow: 0px 0px 0px 2px var(--accent-brand-lighter);
}
}
.reaction-number {
display: inline-block;
vertical-align: 6px;
margin-left: 5px;
vertical-align: 10px;
color: var(--card-color-tertiary);
font-size: 13px;
width: 27px;
@media screen and (min-width: 500px) {
width: 37px;
font-size: 16px;
vertical-align: 9px;
}
@media screen and (min-width: 1365px) {
font-size: 12px;
vertical-align: 9px;
margin-left: 1px;
width: 28px;
}
@media screen and (min-width: 1439px) {
font-size: 15px;
vertical-align: 9px;
width: 37px;
margin-left: 7px;
}
@media screen and (min-width: 1530px) {
font-size: 16px;
vertical-align: 15px;
}
}
&.activated {
img {
filter: none;
opacity: 1;
}
}
&.user-activated {
img {
filter: none;
opacity: 1;
box-shadow: 0px 0px 0px 2px #ffc0d3;
background: linear-gradient(111deg, #ffb4cb, #ff80a8);
}
&.unicorn-reaction-button {
img {
box-shadow: 0px 0px 0px 2px #d0e3ff;
background: linear-gradient(111deg, #c5d9f8, #90bbff);
}
}
&.readinglist-reaction-button {
img {
box-shadow: 0px 0px 0px 2px #cfc9f3;
background: linear-gradient(111deg, #cac3f3, #958aee);
}
}
&.user-animated {
img {
animation: image-reaction-animation 0.3s !important;
}
}
}
}
.article-share-action-block {
display: inline-block;
position: relative;
width: 40px;
button {
min-width: 38px;
opacity: 0.7;
&:hover {
opacity: 1;
}
.dropdown-icon {
vertical-align: -2px;
}
}
img {
background: transparent !important;
}
&:hover {
img {
box-shadow: none !important;
}
}
.dropdown-content {
display: none;
position: fixed;
bottom: 55px;
right: 0;
left: 0;
z-index: 100;
background: var(--header-bg);
font-size: 1em;
text-align: left;
min-width: 300px;
padding-bottom: 15px;
padding-top: 15px;
@media screen and (min-width: 500px) {
position: absolute;
right: -20px;
border-radius: 3px;
font-size: 0.92em;
border: 1px solid $light-medium-gray;
box-shadow: $shadow;
left: auto;
bottom: 48px;
min-width: 312px;
padding-bottom: 6px;
padding-top: 6px;
}
&.showing {
display: block;
}
.dropdown-link-row {
input[type='text'] {
border: 1px dashed black;
padding: 4px 6px;
font-size: 1em;
width: calc(100% - 50px);
border-radius: 3px;
margin: 10px auto 5px;
margin-left: 15px;
}
input[type='checkbox'] {
float: right;
cursor: pointer;
@media screen and (min-width: 400px) {
margin: 5px;
}
@media screen and (min-width: 500px) {
margin: 3px;
}
@media screen and (min-width: 1365px) {
margin: 1px;
}
}
a {
font-weight: bold;
color: var(--body-color);
padding: 12px 18px;
width: calc(100% - 36px);
display: block;
font-size: 0.8em;
}
&.notification-subscriptions-area-row {
padding: 0px;
@include themeable(
border-bottom,
theme-container-border,
1px solid $medium-gray
);
}
.notification-subscriptions-area-header {
padding: 12px 6px;
padding-left: 12px;
font-size: 0.7em;
font-weight: bold;
margin-top: -5px;
@media screen and (min-width: 500px) {
border-top-right-radius: 3px;
border-top-left-radius: 3px;
}
@include themeable-important(
background,
theme-container-background,
darken($tan, 3%)
);
button.notification-subscription-label {
display: inline-block;
width: 90px !important;
margin-left: 5px !important;
text-align: center !important;
float: right !important;
padding: 4px 0px !important;
@include themeable-important(
border,
theme-border,
1px solid $light-medium-gray
);
border-radius: 100px;
&.selected {
visibility: hidden !important;
}
}
}
button.notification-subscription-label {
width: 100% !important;
opacity: 1 !important;
text-align: left;
font-size: 0.8em;
box-sizing: border-box !important;
padding: 13px 4px !important;
padding-left: 13px !important;
margin: auto !important;
cursor: pointer !important;
color: var(--body-color);
.selected-emoji {
visibility: hidden;
margin-left: 4px;
font-size: 1.2em;
vertical-align: -0.1em;
}
&.selected {
.selected-emoji {
display: inline-block;
visibility: visible;
}
color: var(--body-color);
}
}
}
}
}
.article-actions-comments-count {
display: none;
position: relative;
color: var(--card-color-tertiary);
font-weight: bold;
font-size: calc(0.8em + 0.1vw);
vertical-align: calc(7px - 0.07vw);
font-family: $helvetica-condensed;
font-stretch: condensed;
padding: 4px 0.88vw;
border-radius: 3px;
.article-actions-comments-count-number {
display: none;
}
@media screen and (min-width: 620px) {
display: inline-block;
}
@media screen and (min-width: $max-width) {
font-size: 0.92em;
vertical-align: 6px;
}
@media screen and (min-width: 1439px) {
.article-actions-comments-count-number {
display: inline-block;
}
}
}
.article-actions-tweet-button {
padding: 2px 0 2px !important;
border-radius: 3px;
margin-right: 0.15vw;
margin-left: calc(0.2vw + 11px);
vertical-align: calc(3px - 0.07vw);
text-align: center;
width: 50px;
display: none;
img {
height: 23px;
width: 23px;
vertical-align: -4px;
}
@media screen and (min-width: 500px) {
display: inline-block;
vertical-align: calc(6px - 0.07vw);
}
@media screen and (min-width: 1365px) {
padding: 7px 0px !important;
img {
height: 17px;
width: 17px;
}
}
@media screen and (min-width: 1439px) {
padding: 8px 0px !important;
img {
height: 20px;
width: 20px;
}
}
@media screen and (min-width: 1530px) {
padding: 20px 0px 12px !important;
img {
height: 23px;
width: 23px;
}
}
}
}
.html-variant-wrapper {
width: 88%;
margin: 0 auto 25px;
@ -1368,22 +876,6 @@ article {
}
}
.dev-ios-native-body {
.container {
.article-actions {
padding: 4px 0 0;
border-top: 1px solid rgba(0, 0, 0, 0.33);
transition: padding 0.33s;
.article-share-action-block {
.dropdown-content {
bottom: 43px;
}
}
}
}
}
.showpage-reaction-cta {
width: 390px;
max-width: 78%;
@ -1406,20 +898,23 @@ article {
}
.show-comments-header {
width: 800px;
max-width: 90%;
// width: 800px;
// max-width: 90%;
margin: auto;
margin-bottom: -50px;
text-align: center;
font-family: var(--ff-default);
}
.primary-sticky-nav {
display: none;
}
.article-actions {
display: none;
}
.show-comments-footer {
width: 800px;
max-width: 98%;
// width: 800px;
// max-width: 98%;
margin: auto;
margin-top: -80px;
padding-bottom: var(--su-6);
text-align: center;
.full-discussion-button {

View file

@ -123,13 +123,16 @@
}
.crayons-layout--article {
--layout-gap: 0;
@media (min-width: $breakpoint-m) {
--layout-gap: var(--su-2);
--layout-sidebar-left-width: var(--su-9);
--layout: var(--layout-sidebar-left-width) 1fr;
--layout-sidebar-left-row-end: span 2;
}
@media (min-width: $breakpoint-l) {
--layout-gap: var(--su-4);
--layout-sidebar-right-width: 3fr;
--layout-sidebar-left-row-end: initial;
--layout-content-width: 7fr;

View file

@ -126,7 +126,7 @@ a.header-link {
.comments-container {
padding-top: 10px;
margin: auto;
margin-bottom: 100px;
margin-bottom: var(--su-4);
text-align: left;
&.comments-dedicated-page-container {
width: 800px;
@ -143,15 +143,15 @@ a.header-link {
}
.markdown-guide {
position: absolute;
left: 22px;
bottom: 3px;
left: var(--su-1);
bottom: var(--su-1);
}
.editor-image-upload {
display: flex;
align-items: center;
font-size: 0.8em;
position: absolute;
left: calc(0.2vw + 70px);
left: calc(var(--su-8) + var(--su-2));
bottom: 0px;
width: initial;
text-align: left;
@ -202,7 +202,7 @@ a.header-link {
}
.editor-response-templates {
position: absolute;
left: 52px;
left: var(--su-7);
bottom: 4px;
button {
background: none;
@ -257,47 +257,21 @@ a.header-link {
}
}
form {
width: 104%;
@include themeable(
background,
theme-container-accent-background,
$light-gray
);
overflow: auto;
position: relative;
margin-bottom: 4px;
z-index: 4;
margin-left: -2%;
@include themeable(
border-top,
theme-container-border,
1px solid $light-medium-gray
);
@media screen and (min-width: 820px) {
width: calc(100% - 2px);
margin-left: 0%;
@include themeable(
border,
theme-container-border,
1px solid $light-medium-gray
);
}
.field {
margin-bottom: 0px;
}
.response-templates-container {
&.hidden {
display: none;
}
display: flex;
width: calc(100% - 52px);
max-height: calc(40vh + 80px);
margin: 15px auto 2px;
margin-bottom: var(--su-4);
padding-bottom: var(--su-4);
flex-direction: column;
overflow-y: auto;
font-size: 16px;
font-family: var(--ff-default);
font-size: var(--fs-base);
@include themeable(
background,
theme-container-accent-background,
@ -309,9 +283,6 @@ a.header-link {
display: inline-block;
margin: 0 auto;
width: 75px;
&.hidden {
display: none;
}
}
header > button {
@ -425,8 +396,7 @@ a.header-link {
margin-bottom: -5px;
}
textarea {
width: calc(100% - 52px);
margin: 15px auto 2px;
width: 100%;
display: block;
resize: vertical;
border-radius: 3px;
@ -513,8 +483,8 @@ a.header-link {
// this css is added to differentiate the code within a pre tag since pre tag already has black bg.
#preview-div pre code {
background-color: white;
color: black;
background-color: rgba(255, 255, 255, 0.1);
color: rgba(255, 255, 255, 0.9);
}
.actions {
@ -569,7 +539,6 @@ a.header-link {
}
}
input[type='submit'] {
margin-right: 19px;
background: $bold-blue;
}
&.submitting {
@ -872,24 +841,22 @@ a.header-link {
background-color: rgba(0, 0, 0, 0.1);
padding: 0.1em 0.3em 0;
}
.highlight {
display: grid;
justify-content: stretch;
code {
width: 100%;
}
}
pre {
width: 88%;
margin-left: -3%;
margin-left: 0px;
padding-left: 4%;
padding-right: 7%;
padding-top: 6%;
padding-bottom: 6%;
overflow-wrap: normal;
overflow-x: auto;
code {
background: #29292e;
color: black;
color: inherit;
white-space: pre;
font-size: 1em;
background-color: white;
padding-top: 0;
padding-bottom: 2%;
padding: 0;
overflow-x: auto;
}
}
@ -966,27 +933,26 @@ a.header-link {
.dropdown-content {
display: none;
font-size: var(--fs-base);
position: absolute;
right: 0;
border: 1px solid $light-medium-gray;
border-radius: 3px;
background: white;
@include generate-box(
$level: 2,
$bg: var(--card-bg),
$border: var(--card-color),
$color: var(--card-color)
);
z-index: 20;
width: 130px;
box-shadow: $shadow;
width: 160px;
&.showing {
display: block;
}
}
.dropdown-content a {
color: black;
padding: 12px 16px;
width: 98px;
height: 14px;
font-weight: bold;
display: block;
font-size: 14px;
white-space: nowrap;
}

View file

@ -18,7 +18,7 @@
opacity: 0.5;
}
&:hover {
&[href]:hover {
color: var(--tag-color-hover);
}
}

View file

@ -170,7 +170,8 @@
'center': center,
'end': flex-end,
'between': space-between,
'around': space-around
'around': space-around,
'stretch': stretch
),
(),
true

View file

@ -24,7 +24,6 @@
@import 'preact/sidebar-widget';
@import 'preact/article-form';
@import 'tag-edit';
@import 'sticky-nav';
@import 'sidebar-data';
@import 'video-collection';
@import 'listings';

View file

@ -5,7 +5,6 @@
vertical-align: top;
text-align: center;
font-family: var(--ff-default);
margin: 0 auto 32px;
a {
color: var(--body-color);
@ -94,7 +93,6 @@
.show-page-content-display {
vertical-align: top;
font-family: var(--ff-default);
margin: 0 auto 32px;
position: relative;
overflow: hidden;

View file

@ -37,15 +37,15 @@ body {
.zen-mode {
.top-bar,
.primary-sticky-nav,
.article-actions {
display: none !important;
.crayons-article-sticky,
.crayons-article-actions {
display: none;
}
}
@media print {
.top-bar,
.article-actions {
.crayons-article-sticky {
display: none;
}
}
@ -59,7 +59,6 @@ body {
}
.universal-page-content-wrapper {
overflow: hidden;
min-height: 88vh;
visibility: visible;
font-size: 18px;
@ -145,7 +144,6 @@ body.night-theme,
body.ten-x-hacker-theme {
.on-page-nav-butt img,
.icon-img,
.dropdown-icon,
.reaction-button:not(.reacted) img,
.image-upload-button button,
.icon-image,

View file

@ -1,160 +0,0 @@
@import 'variables';
@import 'mixins';
.primary-sticky-nav {
display: none;
@media screen and (min-width: $max-width) {
display: block;
position: fixed;
left: calc(50% + 298px);
top: 70px;
bottom: 20px;
padding: 0 2px;
display: flex;
flex-flow: column wrap;
overflow: hidden;
z-index: 100;
width: 300px;
}
&.hidden {
display: none;
}
.primary-sticky-nav-author {
a {
color: var(--card-color);
}
.primary-sticky-nav-author-top-profile-image {
width: 35px;
height: 35px;
border-radius: 360px;
margin-right: 5px;
vertical-align: -2px;
}
.primary-sticky-nav-author-name {
font-size: 1.3em;
font-weight: bold;
}
.primary-sticky-nav-author-username {
font-size: 0.8em;
font-weight: bold;
}
.primary-sticky-nav-author-summary {
font-weight: 400;
color: var(--card-color-tertiary);
padding: 10px 0px 5px;
font-style: italic;
font-size: 0.88em;
overflow: hidden;
text-overflow: ellipsis;
overflow-wrap: break-word;
}
.primary-sticky-nav-author-follow {
padding-top: 8px;
button {
width: 100%;
font-size: 1.25em;
border: 0px;
border-radius: 3px;
padding: 3px;
height: 44px;
}
}
}
.primary-sticky-nav-profile-image {
height: 23px;
width: 23px;
border-radius: 100px;
vertical-align: -5px;
}
.primary-sticky-nav-title {
padding: 8px 0px 9px;
margin-left: 15px;
font-weight: bold;
img {
width: 19px;
height: 19px;
vertical-align: -1px;
}
a {
color: var(--card-color);
display: inline-block;
}
}
.primary-sticky-nav-element {
display: block;
padding: 10px 13px;
font-size: 0.9em;
font-weight: bold;
@include dev-card;
margin-left: 10px;
color: var(--card-color);
width: 262px;
border-radius: 3px;
.primary-sticky-nav-element-details {
margin-top: 9px;
font-size: 0.8em;
color: var(--card-color-tertiary);
}
}
.user-metadata-details {
margin-top: 10px;
margin-left: 2px;
font-family: var(--ff-accent);
.row {
padding: calc(3px + 0.1vw) 0px;
display: inline-block;
width: 96%;
}
.key {
font-size: 0.8em;
font-weight: 800;
margin-bottom: 2px;
color: var(--card-color-tertiary);
}
.value {
display: inline-block;
font-size: 0.92em;
margin-bottom: 4px;
}
}
.html-variant-wrapper {
margin: 10px;
}
}
.primary-sticky-nav-org-summary {
font-weight: 400;
color: var(--card-color);
padding: 4px 0px;
font-size: 0.95em;
margin-top: 20px;
border-top: 1px solid $light-medium-gray;
p {
margin: 12px 0px;
}
code {
background: $light-gray;
border-radius: 3px;
padding: 3px 4px;
color: #333842;
font-family: var(--ff-accent);
}
.primary-sticky-nav-org-cta-link-wrapper {
text-align: center;
}
a.primary-sticky-nav-org-cta-link {
display: inline-block;
font-size: 1.25em;
border: 0px;
border-radius: 100px;
padding: 6px 38px;
margin-top: 20px;
background: white;
color: $black;
font-family: $helvetica-condensed;
font-weight: bold;
text-align: center;
font-stretch: condensed;
margin-bottom: 5px;
}
}

View file

@ -4,7 +4,7 @@ div.highlight pre.highlight code {
}
div.inner-comment div.body div.highlight pre.highlight {
background: #29292e;
background: #08090a;
code {
font-size: inherit;
white-space: inherit;
@ -13,7 +13,7 @@ div.inner-comment div.body div.highlight pre.highlight {
}
}
$code-highlight-background-color: #29292e;
$code-highlight-background-color: #08090a;
$code-highlight-text-color: #f8f8f2;
$code-highlight-comment-color: #808080;
$code-highlight-declaration-color: #f39c12;

View file

@ -214,8 +214,6 @@
}
}
.user-metadata-details {
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier,
monospace;
width: 97%;
overflow-y: auto;
@media screen and (min-width: 1100px) {
@ -236,7 +234,6 @@
position: absolute;
top: 45%;
transform: translateY(-45%);
border-left: 3px solid $outline-color;
padding: 15px 0px;
}
.row {

View file

@ -75,7 +75,6 @@
display: flex;
flex-direction: column;
height: 100%;
padding: var(--article-padding-y) var(--article-padding-x);
overflow: auto;
height: calc(
100vh - var(--header-height) - var(--article-form-actions-height)
@ -162,7 +161,7 @@
&__toolbar {
position: sticky;
top: calc(var(--article-padding-y) * -1);
top: 0;
background: var(--base-0);
padding: var(--su-2) var(--article-padding-x);
margin: calc(var(--article-padding-y) * -1)
@ -207,7 +206,6 @@
&__tagsfield {
position: relative;
margin-bottom: calc(var(--article-padding-y) * 2);
}
&__help {

View file

@ -4,55 +4,76 @@
--article-rythm: var(--su-2);
--article-padding-x: var(--su-3);
--article-padding-y: var(--su-3);
--article-font-size: var(--fs-l);
@media (min-width: $breakpoint-s) {
--article-padding-x: var(--su-4);
--article-padding-y: var(--su-4);
--article-padding-x: var(--su-5);
--article-padding-y: var(--su-5);
}
@media (min-width: $breakpoint-m) {
--article-rythm: var(--su-4);
--article-padding-x: var(--su-6);
--article-padding-y: var(--su-6);
--article-padding-x: var(--su-8);
--article-padding-y: var(--su-7);
--article-font-size: var(--fs-xl);
}
@media (min-width: $breakpoint-l) {
--article-padding-x: var(--su-8);
@media (min-width: $breakpoint-xl) {
--article-padding-x: var(--su-9);
}
}
.crayons-article {
&__cover {
margin: calc(var(--article-padding-y) * -1)
calc(var(--article-padding-x) * -1) var(--article-padding-x)
calc(var(--article-padding-x) * -1);
width: calc(100% + (var(--article-padding-x) * 2));
position: relative;
width: 100%;
padding-top: 42%;
&__image {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: var(--radius) var(--radius) 0 0;
background-size: cover;
background-position: center center;
padding-top: 42%;
object-fit: cover;
width: 100%;
height: 100%;
}
}
&__video {
background: black;
&__player {
&:empty {
width: 100%;
padding-top: 56.25%;
}
}
}
&__header {
margin-bottom: var(--su-6);
margin-bottom: var(--article-padding-y);
&__meta {
padding: var(--article-padding-y) var(--article-padding-x) 0
var(--article-padding-x);
}
}
&__tags {
// TODO: replace with actual component one day...
font-family: var(--ff-accent);
font-size: var(--fs-s);
&__subheader {
font-size: var(--fs-base);
color: var(--base-60);
display: flex;
flex-wrap: wrap;
align-items: center;
}
&__body {
font-size: var(--fs-l);
font-family: var(--ff-serif);
@media (min-width: $breakpoint-m) {
font-size: var(--fs-xl);
}
padding: 0 var(--article-padding-x) var(--article-padding-y)
var(--article-padding-x);
font-size: var(--article-font-size);
a {
code {
@ -222,36 +243,47 @@
}
pre {
background: #29292e;
background: #08090a;
overflow-x: auto;
color: #eff0f9;
padding: var(--su-6) var(--su-8);
padding: var(--article-padding-y) var(--article-padding-x);
margin: var(--article-rythm) 0;
margin-left: calc(var(--su-8) * -1);
margin-right: calc(var(--su-8) * -1);
width: calc(100% + var(--su-8) + var(--su-8));
margin-left: calc(var(--article-padding-x) * -1);
margin-right: calc(var(--article-padding-x) * -1);
width: calc(100% + var(--article-padding-x) + var(--article-padding-x));
overflow-wrap: normal;
border-radius: 0;
code {
background: #29292e;
background: #08090a;
color: #eff0f9;
white-space: pre;
}
}
.highlight {
display: grid;
justify-content: stretch;
margin-left: calc(var(--article-padding-x) * -1);
margin-right: calc(var(--article-padding-x) * -1);
pre.highlight {
display: block;
margin: 0;
margin-left: 0;
margin-right: 0;
width: 100%;
}
}
img {
height: auto;
position: relative;
display: block;
margin: auto;
left: -4%;
max-width: 108%;
@media screen and (min-width: 430px) {
left: -6px;
max-width: calc(100% + 12px);
}
max-width: 100%;
max-height: calc(50vh + 180px);
border-radius: var(--radius);
}
a.article-body-image-wrapper {
@ -276,16 +308,6 @@
width: 100%;
margin-left: 0%;
overflow-x: auto;
@media screen and (min-width: 430px) {
width: 108%;
margin-left: -4%;
}
@media screen and (min-width: 800px) {
width: 110%;
margin-left: -5%;
}
}
table {
@ -294,10 +316,6 @@
margin: 0.8em auto 1.2em;
table-layout: fixed;
@media screen and (min-width: 500px) {
font-size: 0.9em;
}
th {
border: 1px solid rgba(0, 0, 0, 0.1);
padding: 5px 1vw;
@ -317,6 +335,222 @@
}
}
.crayons-article-actions {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: var(--su-2);
@supports (padding-button: constant(safe-area-inset-bottom)) {
padding-bottom: env(safe-area-inset-bottom);
}
display: flex;
align-items: center;
background: var(--body-bg);
box-shadow: 0 -1px 1px rgba(0, 0, 0, 0.1);
z-index: 200;
justify-content: space-around;
@media (min-width: $breakpoint-m) {
padding: 0;
padding-bottom: 0;
display: grid;
gap: var(--su-6);
position: sticky;
box-shadow: none;
justify-content: stretch;
top: calc(var(--header-height) + var(--layout-padding) + 6vh);
.static-navbar-config & {
top: var(--layout-padding);
}
}
}
.crayons-reaction {
--reaction-color: var(--button-ghost-color);
--reaction-border: inset 0 0 0 0 transparent;
--reaction-bg: transparent;
border: none;
padding: 0;
background: transparent;
display: inline-flex;
flex-direction: row;
align-items: center;
@media (min-width: $breakpoint-m) {
flex-direction: column;
}
&__icon {
padding: var(--su-2);
box-shadow: var(--reaction-border);
background: var(--reaction-bg);
color: var(--reaction-color);
border-radius: 50%;
transition: all var(--transition-props);
&--active {
display: none;
}
}
&__count {
color: var(--base-70);
font-size: var(--fs-s);
display: block;
min-width: var(--su-7);
@media (min-width: $breakpoint-m) {
min-width: auto;
}
}
&.user-activated {
--reaction-border: inset 0 0 0 2px var(--reaction-color);
.crayons-reaction__icon--inactive {
display: none;
}
.crayons-reaction__icon--active {
display: block;
}
.crayons-reaction__count {
color: var(--reaction-color);
}
}
&--like {
&:hover,
&.user-activated {
--reaction-color: var(--accent-danger);
--reaction-bg: var(--accent-danger-a10);
}
}
&--unicorn {
&:hover,
&.user-activated {
--reaction-color: var(--accent-success-darker);
--reaction-bg: var(--accent-success-a10);
}
}
&--readinglist {
&:hover,
&.user-activated {
--reaction-color: var(--accent-brand);
--reaction-bg: var(--accent-brand-a10);
}
}
}
.user-animated {
.crayons-reaction__icon {
position: relative;
&:before {
content: '';
position: absolute;
pointer-events: none;
left: 0;
top: 0;
right: 0;
bottom: 0;
border-radius: 50%;
box-shadow: 0 0 0 4px currentColor;
opacity: 0;
transform: scale(2);
animation-name: ringPop;
animation-duration: 0.25s;
}
&:after {
content: '';
position: absolute;
pointer-events: none;
left: 0;
top: 0;
right: 0;
bottom: 0;
border-radius: 50%;
box-shadow: 0 0 0 0 transparent;
opacity: 0;
transform: scale(1);
animation-name: ringPop2;
animation-duration: 0.75s;
}
animation-name: iconPop;
animation-duration: 0.25s;
}
@keyframes iconPop {
0% {
transform: scale(0.65);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
@keyframes ringPop {
0% {
transform: scale(2);
box-shadow: 0 0 0 4px currentColor;
opacity: 0;
}
100% {
box-shadow: 0 0 0 1px currentColor;
transform: scale(1);
opacity: 1;
}
}
@keyframes ringPop2 {
0% {
box-shadow: 0 0 0 currentColor;
transform: scale(1);
opacity: 0.6;
}
100% {
box-shadow: 0 0 1px 1px transparent;
transform: scale(4);
opacity: 0;
}
}
}
.crayons-article-sticky {
position: sticky;
top: calc(var(--header-height) + var(--layout-padding));
.static-navbar-config & {
top: var(--layout-padding);
}
}
.user-metadata-details {
li + li {
margin-top: var(--su-3);
}
.key {
font-size: var(--fs-xs);
font-weight: var(--fw-bold);
text-transform: uppercase;
color: var(--card-color-tertiary);
}
}
.text-padding {
padding: var(--article-padding-y) var(--article-padding-x);
}
.crayons-article {
.article-collection-wrapper {
font-family: var(--ff-default);

View file

@ -119,11 +119,11 @@ module ApplicationHelper
tags: %w[p b i em strike strong u br]
end
def follow_button(followable, style = "full")
def follow_button(followable, style = "full", classes = "")
return if followable == DELETED_USER
tag :button, # Yikes
class: "cta follow-action-button",
class: "crayons-btn follow-action-button " + classes,
data: {
:info => { id: followable.id, className: followable.class.name, style: style }.to_json,
"follow-action-button" => true

View file

@ -78,7 +78,9 @@ exports[`<ArticleForm /> renders properly 1`] = `
<div
class="crayons-article-form__content crayons-card"
>
<div>
<div
class="text-padding"
>
<div
class="crayons-article-form__cover"
role="presentation"
@ -154,7 +156,7 @@ exports[`<ArticleForm /> renders properly 1`] = `
</div>
</div>
<div
class="crayons-article-form__body"
class="crayons-article-form__body text-padding"
>
<div
class="crayons-article-form__toolbar false"

View file

@ -10,7 +10,7 @@ export const EditorBody = ({
version,
}) => {
return (
<div className="crayons-article-form__body">
<div className="crayons-article-form__body text-padding">
<Toolbar version={version} />
<Textarea

View file

@ -14,7 +14,7 @@ export const Meta = ({
switchHelpContext,
}) => {
return (
<div>
<div className="text-padding">
<ArticleCoverImage
mainImage={mainImage}
onMainImageUrlChange={onMainImageUrlChange}

View file

@ -36,18 +36,23 @@ function titleArea(previewResponse, articleState, errors) {
<header className="crayons-article__header">
{coverImage.length > 0 && (
<div className="crayons-article__cover">
<div
<img
className="crayons-article__cover__image"
style={{ backgroundImage: `url(${coverImage})` }}
src={coverImage}
width="1000"
height="420"
alt=""
/>
</div>
)}
{errors && <ErrorList errors={errors} />}
<h1 className="fs-3xl s:fs-4xl l:fs-5xl fw-bold s:fw-heavy lh-tight mb-6 spec-article__title">
{previewTitle}
</h1>
<div className="crayons-article__header__meta">
{errors && <ErrorList errors={errors} />}
<h1 className="fs-3xl s:fs-4xl l:fs-5xl fw-bold s:fw-heavy lh-tight mb-6 spec-article__title">
{previewTitle}
</h1>
<div className="crayons-article__tags">{tags}</div>
<div className="spec-article__tags">{tags}</div>
</div>
</header>
);
}

View file

@ -97,7 +97,7 @@ describe('<Preview />', () => {
/>,
);
expect(container.find('.crayons-article__tags').text()).toEqual(
expect(container.find('.spec-article__tags').text()).toEqual(
'#javascript#career',
);
});

View file

@ -5,7 +5,7 @@ exports[`<Form /> v1 renders properly 1`] = `
class="crayons-article-form__content crayons-card"
>
<div
class="crayons-article-form__body"
class="crayons-article-form__body text-padding"
>
<div
class="crayons-article-form__toolbar border-t-0"
@ -75,7 +75,9 @@ exports[`<Form /> v2 renders properly 1`] = `
<div
class="crayons-article-form__content crayons-card"
>
<div>
<div
class="text-padding"
>
<div
class="crayons-article-form__cover"
role="presentation"
@ -166,7 +168,7 @@ exports[`<Form /> v2 renders properly 1`] = `
</div>
</div>
<div
class="crayons-article-form__body"
class="crayons-article-form__body text-padding"
>
<div
class="crayons-article-form__toolbar false"

View file

@ -13,43 +13,46 @@ exports[`<Preview /> renders properly 1`] = `
<div
class="crayons-article__cover"
>
<div
<img
alt=""
class="crayons-article__cover__image"
style={
Object {
"backgroundImage": "url(/i/9ca8kb1cu34mobypm5yx.png)",
}
}
height="420"
src="/i/9ca8kb1cu34mobypm5yx.png"
width="1000"
/>
</div>
<h1
class="fs-3xl s:fs-4xl l:fs-5xl fw-bold s:fw-heavy lh-tight mb-6 spec-article__title"
>
My Awesome Post
</h1>
<div
class="crayons-article__tags"
class="crayons-article__header__meta"
>
<span
class="crayons-tag mr-2"
<h1
class="fs-3xl s:fs-4xl l:fs-5xl fw-bold s:fw-heavy lh-tight mb-6 spec-article__title"
>
My Awesome Post
</h1>
<div
class="spec-article__tags"
>
<span
class="crayons-tag__prefix"
class="crayons-tag mr-2"
>
#
<span
class="crayons-tag__prefix"
>
#
</span>
javascript
</span>
javascript
</span>
<span
class="crayons-tag mr-2"
>
<span
class="crayons-tag__prefix"
class="crayons-tag mr-2"
>
#
<span
class="crayons-tag__prefix"
>
#
</span>
career
</span>
career
</span>
</div>
</div>
</header>
<div

View file

@ -13,11 +13,11 @@ class StickyArticleCollection
limited_column_select.
tagged_with(article_tags, any: true).
where.not(id: article.id).order("published_at DESC").
limit(2)
limit(3)
end
def suggested_stickies
(tag_articles.load + more_articles).sample(8)
(tag_articles.load + more_articles).sample(3)
end
def tag_articles
@ -27,7 +27,7 @@ class StickyArticleCollection
where.not(id: article.id).where.not(user_id: article.user_id).
where("featured_number > ?", 5.days.ago.to_i).
order(Arel.sql("RANDOM()")).
limit(8)
limit(3)
end
def more_articles

View file

@ -1,4 +1,4 @@
<div class="container show-page-content-display"
<div class="crayons-card crayons-card--secondary show-page-content-display"
data-details="<%= article.organization&.slug %>__<%= article.slug %>"
id="<%= classification == "boosted" ? "partner-content-display" : "classic_article_#{article.id}" %>">
<div class="content-classification">

View file

@ -1,34 +1,44 @@
<div class="about-the-author" id="about-the-author">
<div class="left-column">
<a href="/<%= @user.username %>">
<img class="profile-pic" src="<%= ProfileImage.new(@user).get(width: 180) %>" alt="<%= @user.username %> profile" />
<div>
<p class="mb-4 color-base-60 fs-s">Posted on <%= published %> by:</p>
<div class="flex">
<a href="/<%= @user.username %>" class="crayons-avatar crayons-avatar--2xl shrink-0 mr-4">
<img class="crayons-avatar__image" src="<%= ProfileImage.new(@user).get(width: 180) %>" alt="<%= @user.username %> profile" />
</a>
</div>
<div class="main-content">
<h4><a href="/<%= @user.username %>"><%= @user.name %></a><%= follow_button(@user) %></h4>
<p><%= @user.summary %></p>
<p class="social">
<a href="/<%= @user.username %>">
@<%= @user.username %>
</a>
<% if @user.twitter_username.present? %>
<a href="http://twitter.com/<%= @user.twitter_username %>" target="_blank" rel="noopener">
<%= inline_svg_tag("twitter.svg", aria: true, class: "crayons-icon", width: 24, height: 24, title: "Twitter") %>
<%= @user.twitter_username %>
<div>
<h3 class="fs-l s:fs-xl m:fs-2xl l:fs-3xl fw-medium"><a href="/<%= @user.username %>" class="crayons-link"><%= @user.name %></a></h3>
<p class="fw-medium mb-2">
<a href="/<%= @user.username %>" class="crayons-link crayons-link--secondary">
@<%= @user.username %>
</a>
</p>
<% if @user.summary %>
<p class="color-base-70 mb-4"><%= @user.summary %></p>
<% end %>
<% if @user.github_username.present? %>
<a href="http://github.com/<%= @user.github_username %>" target="_blank" rel="noopener">
<%= inline_svg_tag("github.svg", aria: true, class: "crayons-icon", width: 24, height: 24, title: "GitHub") %>
<%= @user.github_username %>
</a>
<% end %>
<% if @user.website_url.present? %>
<a href="<%= @user.website_url %>" target="_blank" rel="noopener">
<%= inline_svg_tag("link-external.svg", aria: true, class: "crayons-icon", width: 24, height: 24, title: "Website") %>
<%= beautified_url(@user.website_url) %>
</a>
<% end %>
</p>
<div class="flex items-center">
<div><%= follow_button(@user) %>&nbsp;</div>
<% if @user.twitter_username.present? || @user.github_username.present? || @user.website_url.present? %>
<div class="flex items-center fs-s">
<% if @user.twitter_username.present? %>
<a href="http://twitter.com/<%= @user.twitter_username %>" target="_blank" rel="noopener" class="crayons-link crayons-link--secondary ml-4">
<%= inline_svg_tag("twitter.svg", aria: true, class: "crayons-icon", width: 24, height: 24, title: "Twitter") %>
</a>
<% end %>
<% if @user.github_username.present? %>
<a href="http://github.com/<%= @user.github_username %>" target="_blank" rel="noopener" class="crayons-link crayons-link--secondary ml-4">
<%= inline_svg_tag("github.svg", aria: true, class: "crayons-icon", width: 24, height: 24, title: "GitHub") %>
</a>
<% end %>
<% if @user.website_url.present? %>
<a href="<%= @user.website_url %>" target="_blank" rel="noopener" class="crayons-link crayons-link--secondary ml-4">
<%= inline_svg_tag("link-external.svg", aria: true, class: "crayons-icon", width: 24, height: 24, title: "Website") %>
</a>
<% end %>
</div>
<% end %>
</div>
</div>
</div>
</div>

View file

@ -1,103 +1,86 @@
<div class="article-actions" id="article-reaction-actions">
<div class="crayons-article-actions">
<% if @article.published? %>
<%= render partial: "articles/reaction_button",
locals: {
category: :like,
description: "heart",
image_path: "emoji/emoji-one-heart.png"
description: "Heart",
image_path: "heart.svg",
image_active_path: "heart-filled.svg"
} %>
<%= render partial: "articles/reaction_button",
locals: {
category: :unicorn,
description: "unicorn",
image_path: "emoji/emoji-one-unicorn.png"
description: "Unicorn",
image_path: "unicorn.svg",
image_active_path: "unicorn-filled.svg"
} %>
<%= render partial: "articles/reaction_button",
locals: {
category: :readinglist,
description: "reading list",
image_path: "emoji/emoji-one-bookmark.png"
description: "Reading list",
image_path: "save.svg",
image_active_path: "save-filled.svg"
} %>
<% display_name = @article.user.twitter_username ? "@" + @article.user.twitter_username : @article.user.name %>
<a
class="article-actions-tweet-button"
rel="noopener"
target="_blank"
href='https://twitter.com/intent/tweet?text="<%= u @article.title.strip %>" by <%= display_name %> <%= u SiteConfig.twitter_hashtag %> <%= article_url(@article) %>'>
<img src="<%= asset_path("twitter.svg") %>" alt="twitter logo">
</a>
<% end %>
<a class="article-actions-comments-count" href="#comments" id="jump-to-comments">
DISCUSS
<% if @article.comments_count.positive? %>
<span class="article-actions-comments-count-number">(<%= @article.comments_count %>)</span>
<% else %>
<% end %>
</a>
<div class="article-share-action-block">
<button id="article-show-more-button" class="dropbtn" aria-label="Toggle dropdown menu">
<img src="<%= asset_path("three-dots.svg") %>" class="dropdown-icon" alt="dropdown menu icon">
<div class="align-center m:relative">
<button id="article-show-more-button" class="dropbtn crayons-btn crayons-btn--ghost crayons-btn--icon-rounded" aria-label="Toggle dropdown menu">
<%= inline_svg_tag("overflow-horizontal.svg", aria: true, class: "dropdown-icon crayons-icon", title: "More...") %>
</button>
<div class="dropdown-content">
<div>
<div class="dropdown-link-row">
<clipboard-copy for="article-copy-link-input" aria-live="polite" aria-controls="article-copy-link-announcer">
<input type="text" id="article-copy-link-input" value="<%= article_url(@article) %>" readonly />
<img id="article-copy-icon" src="<%= asset_path("content-copy.svg") %>" alt="Copy to Clipboard" />
<span id="article-copy-link-announcer" role="alert" hidden>Copied to Clipboard</span>
</clipboard-copy>
<div class="crayons-dropdown p-1 z-30 right-1 left-1 s:left-auto bottom-100 m:bottom-auto m:right-auto m:left-100 m:top-0 fs-base">
<clipboard-copy for="article-copy-link-input" aria-live="polite" aria-controls="article-copy-link-announcer" class="dropdown-link-row">
<div class="flex items-center">
<input type="text" id="article-copy-link-input" value="<%= article_url(@article) %>" class="crayons-textfield" readonly />
<%= inline_svg_tag("copy.svg", aria: true, id: "article-copy-icon", class: "crayons-icon mx-2 shrink-0", title: "Notifications") %>
</div>
<web-share-wrapper shareurl="<%= article_url(@article) %>" sharetext="<%= @article.title %>" template="web-share-button">
<div class="dropdown-link-row">
<a
target="_blank"
rel="noopener"
href='https://twitter.com/intent/tweet?text="<%= u @article.title.strip %>" by <%= @article.user.twitter_username ? "@" + @article.user.twitter_username : @article.user.name %> <%= u SiteConfig.twitter_hashtag %> <%= article_url(@article) %>'>
Share to Twitter
</a>
</div>
<div class="dropdown-link-row">
<a
target="_blank"
rel="noopener"
href="https://www.linkedin.com/shareArticle?mini=true&url=<%= article_url(@article) %>&title=<%= @article.title %>&summary=<%= @article.description %>&source=<%= community_name %>">
Share to LinkedIn
</a>
</div>
<div class="dropdown-link-row">
<a
target="_blank"
rel="noopener"
href="https://www.reddit.com/submit?url=<%= article_url(@article) %>&title=<%= @article.title %>">
Share to Reddit
</a>
</div>
<div class="dropdown-link-row">
<a
target="_blank"
rel="noopener"
href="https://news.ycombinator.com/submitlink?u=<%= article_url(@article) %>&t=<%= @article.title %>">
Share to Hacker News
</a>
</div>
<div class="dropdown-link-row">
<a
target="_blank"
rel="noopener"
href="https://www.facebook.com/sharer.php?u=<%= article_url(@article) %>">
Share to Facebook
</a>
</div>
</web-share-wrapper>
<template id="web-share-button">
<div class="dropdown-link-row"><a href="#">Share Post</a></div>
</template>
<div class="dropdown-link-row"><a href="/report-abuse">Report Abuse</a></div>
</div>
<div id="article-copy-link-announcer" role="alert" class="crayons-notice crayons-notice--success my-2 p-1" hidden>Copied to Clipboard</div>
</clipboard-copy>
<web-share-wrapper shareurl="<%= article_url(@article) %>" sharetext="<%= @article.title %>" template="web-share-button">
<a
target="_blank"
class="dropdown-link-row crayons-link crayons-link--block"
rel="noopener"
href='https://twitter.com/intent/tweet?text="<%= u @article.title.strip %>" by <%= @article.user.twitter_username ? "@" + @article.user.twitter_username : @article.user.name %> <%= u SiteConfig.twitter_hashtag %> <%= article_url(@article) %>'>
Share to Twitter
</a>
<a
target="_blank"
class="dropdown-link-row crayons-link crayons-link--block"
rel="noopener"
href="https://www.linkedin.com/shareArticle?mini=true&url=<%= article_url(@article) %>&title=<%= @article.title %>&summary=<%= @article.description %>&source=<%= community_name %>">
Share to LinkedIn
</a>
<a
target="_blank"
class="dropdown-link-row crayons-link crayons-link--block"
rel="noopener"
href="https://www.reddit.com/submit?url=<%= article_url(@article) %>&title=<%= @article.title %>">
Share to Reddit
</a>
<a
target="_blank"
class="dropdown-link-row crayons-link crayons-link--block"
rel="noopener"
href="https://news.ycombinator.com/submitlink?u=<%= article_url(@article) %>&t=<%= @article.title %>">
Share to Hacker News
</a>
<a
target="_blank"
class="dropdown-link-row crayons-link crayons-link--block"
rel="noopener"
href="https://www.facebook.com/sharer.php?u=<%= article_url(@article) %>">
Share to Facebook
</a>
</web-share-wrapper>
<template id="web-share-button">
<a href="#" class="dropdown-link-row crayons-link crayons-link--block">Share Post</a>
</template>
<a href="/report-abuse" class="dropdown-link-row crayons-link crayons-link--block">Report Abuse</a>
</div>
</div>
</div>
<% if !user_signed_in? && @article.body_markdown.size > 900 %>
<% cache("below-article-html-variant-#{rand(20)}", expires_in: 8.hours) do %>
<% @html_variant = HtmlVariant.find_for_test(@article.cached_tag_list_array, "article_show_below_article_cta") %>

View file

@ -1,5 +1,5 @@
<% if articles %>
<div class="more-articles container">
<div class="more-articles crayons-card crayons-card--secondary">
<% articles.each do |article| %>
<a href="<%= article.path %>" data-preload-image="<%= cloud_cover_url(article.main_image) %>">
<div class="single-other-article">

View file

@ -1,12 +1,12 @@
<% cache("whole-comment-area-#{@article.id}-#{@article.last_comment_at}-#{@article.show_comments}", expires_in: 2.hours) do %>
<div id="comments" data-updated-at="<%= Time.current %>">
<section id="comments" data-updated-at="<%= Time.current %>" class="crayons-card text-padding">
<% if @article.show_comments %>
<div class="relative flex justify-between items-center mx-2 s:mx-7 mb-2" style="min-height:40px;margin-top:15px;">
<span class="fs-2xl fw-bold">Discussion</span>
<div id="comment-subscription"></div>
</div>
<header class="relative flex justify-between items-center">
<h3 class="fs-2xl fw-bold">Discussion</h3>
<div id="comment-subscription"><span class="crayons-btn crayons-btn--outlined">Subscribe</span></div>
</header>
<div
class="comments-container mx-2 s:mx-7"
class="comments-container"
id="comments-container"
data-commentable-id="<%= @article.id %>"
data-commentable-type="Article">
@ -27,6 +27,6 @@
<%= render "articles/comments_actions" %>
</div>
<% end %>
</div>
</section>
<% end %>
<% return if @warm_only %>

View file

@ -1,25 +1,29 @@
<% if organization && organization.bg_color_hex.present? %>
<div class="org-branding" id="org-branding">
<div class="inner">
<div class="content">
<div class="name"><a href="/<%= organization.slug %>"><%= organization.name %></a></div>
<div class="summary"><%= organization.summary %></div>
<p class="social">
<div class="flex <% if author == true %>mt-6<% end %>">
<a href="/<%= organization.slug %>" class="crayons-avatar crayons-avatar--2xl shrink-0 mr-4">
<% cache("article-organization-image-#{organization.id}-#{organization.updated_at.rfc3339}", expires_in: 100.hours) do %>
<img src="<%= ProfileImage.new(organization).get %>" alt="<%= organization.name %>" class="crayons-logo__image" />
<% end %>
</a>
<div>
<h3 class="fs-l s:fs-xl m:fs-2xl l:fs-3xl fw-medium"><a href="/<%= organization.slug %>" class="crayons-link"><%= organization.name %></a></h3>
<% if organization.summary %>
<div class="color-base-70 mb-4"><%= organization.summary %></div>
<% end %>
<% if organization.twitter_username.present? || organization.website_url.present? %>
<div class="social">
<% if organization.twitter_username.present? %>
<a href="https://twitter.com/<%= organization.twitter_username %>" target="_blank" rel="noopener">@<%= organization.twitter_username %></a>
<a href="https://twitter.com/<%= organization.twitter_username %>" target="_blank" class="crayons-link crayons-link--secondary" rel="noopener" title="@<%= organization.twitter_username %>">
<%= inline_svg_tag("twitter.svg", aria: true, class: "crayons-icon", width: 24, height: 24, title: "Twitter") %>
</a>
<% end %>
<% if organization.website_url.present? %>
<a href="<%= organization.website_url %>" target="_blank" rel="noopener"><%= beautified_url organization.website_url %></a>
<a href="<%= organization.website_url %>" target="_blank" rel="noopener" class="ml-2 crayons-link crayons-link--secondary" title="<%= beautified_url organization.website_url %>">
<%= inline_svg_tag("link-external.svg", aria: true, class: "crayons-icon", width: 24, height: 24, title: "Website") %>
</a>
<% end %>
</p>
</div>
<div class="profile-image">
<a href="/<%= organization.slug %>">
<% cache("article-organization-image-#{organization.id}-#{organization.updated_at.rfc3339}", expires_in: 100.hours) do %>
<img src="<%= ProfileImage.new(organization).get %>" alt="<%= organization.name %>" />
<% end %>
</a>
</div>
</div>
<% end %>
</div>
</div>
<% end %>

View file

@ -1,12 +1,14 @@
<button
role="checkbox"
id="reaction-butt-<%= category %>"
class="article-reaction-butt <%= category %>-reaction-button"
class="crayons-reaction crayons-reaction--<%= category %>"
data-category="<%= category %>"
alt="<%= description %>"
title="<%= description %>">
<img
alt="<%= description %>"
src="<%= asset_path(image_path) %>" />
<span class="reaction-number" id="reaction-number-<%= category %>" alt="count"></span>
<span class="crayons-reaction__icon crayons-reaction__icon--inactive">
<%= inline_svg_tag(image_path, aria: true, class: "crayons-icon", title: description) %>
</span>
<span class="crayons-reaction__icon crayons-reaction__icon--active">
<%= inline_svg_tag(image_active_path, aria: true, class: "crayons-icon", title: description) %>
</span>
<span class="crayons-reaction__count" id="reaction-number-<%= category %>" alt="count"><span class="bg-base-40 opacity-25 p-2 inline-block radius-default"></span></span>
</button>

View file

@ -34,91 +34,99 @@
}
</style>
<div class="primary-sticky-nav" id="article-show-primary-sticky-nav">
<div class="primary-sticky-nav-element primary-sticky-nav-author">
<a href="<%= @actor.path %>"><img src="<%= ProfileImage.new(@actor).get(width: 90) %>" class="primary-sticky-nav-author-top-profile-image" alt="<%= @actor.name %> profile image"></a>
<div style="display:inline-block">
<div class="primary-sticky-nav-author-name">
<a href="<%= @actor.path %>">
<%= @actor.name %>
</a>
</div>
<div class="primary-sticky-nav-author-username">
<a href="<%= @actor.path %>">
@<%= @actor.username %>
</a>
</div>
<style>
.crayons-card--branded {
border-top: 32px solid <%= HexComparer.new([user_colors(@actor)[:bg], user_colors(@actor)[:text]]).brightness(0.88) %>;
}
</style>
<div class="crayons-article-sticky grid gap-4" id="article-show-primary-sticky-nav">
<div class="crayons-card crayons-card--secondary crayons-card--branded p-4 pt-0 hidden l:grid gap-4">
<div class="-mt-4">
<a href="<%= @actor.path %>" class="flex items-end">
<span class="<% if @actor.class.name == "User" %>crayons-avatar crayons-avatar--xl<% elsif @actor.class.name == "Organization" %>crayons-logo crayons-logo--xl<% end %> mr-2">
<img src="<%= ProfileImage.new(@actor).get(width: 90) %>" class="<% if @actor.class.name == "User" %>crayons-avatar__image<% elsif @actor.class.name == "Organization" %>crayons-logo__image<% end %>" alt="<%= @actor.name %> profile image">
</span>
<span class="crayons-link fs-l fw-bold"><%= @actor.name %></span>
</a>
</div>
<div class="primary-sticky-nav-author-summary">
<% if @actor.tag_line.present? %>
<% if @actor.tag_line.present? %>
<div class="color-base-70">
<%= truncate (@actor.tag_line || @actor.summary || "Posts in this tag"), length: 200 %>
<% end %>
</div>
<div class="primary-sticky-nav-author-follow">
<%= follow_button(@actor) %>
</div>
<% end %>
<div>
<%= follow_button(@actor, style = "", classes = "w-100") %>&nbsp;
</div>
<% if @actor.class.name == "User" %>
<%= render "articles/user_metadata", context: "sidebar" %>
<% elsif @actor.class.name == "Organization" && @actor.approved_and_filled_out_cta? %>
<div class="primary-sticky-nav-org-summary">
<div>
<%= sanitize_rendered_markdown(@actor.cta_processed_html) %>
<div class="primary-sticky-nav-org-cta-link-wrapper">
<% if @actor.cta_button_text.present? && @actor.cta_button_url.present? %>
<a href="<%= @actor.cta_button_url || "LEARN MORE" %>" class="primary-sticky-nav-org-cta-link">
<%= @actor.cta_button_text %>
</div>
<% if @actor.cta_button_text.present? && @actor.cta_button_url.present? %>
<div>
<a href="<%= @actor.cta_button_url || "Learn more" %>" class="crayons-btn crayons-btn--outlined w-100">
<%= @actor.cta_button_text %>
</a>
</div>
<% end %>
<% end %>
</div>
<% cache("article-sticky-nav-articles-0-#{@article.id}-#{@actor.last_article_at}", expires_in: 48.hours) do %>
<% @sticky_collection = StickyArticleCollection.new(@article, @organization || @user) %>
<% @sticky_articles = @sticky_collection.suggested_stickies %>
<% @user_stickies = @sticky_collection.user_stickies %>
<% if @user_stickies.present? %>
<div class="crayons-card crayons-card--secondary">
<header class="crayons-card__header">
<h3 class="crayons-card__header__headline">
More from <a href="<%= @actor.path %>"><%= @actor.name %></a>
</h3>
</header>
<div>
<% @user_stickies.each_with_index do |article, index| %>
<a class="crayons-link crayons-link--contentful" href="<%= article.path %>">
<%= article.title %>
<div class="crayons-link__secondary -ml-1">
<% article.decorate.cached_tag_list_array.each do |tag| %>
<span class="crayons-tag"><span class="crayons-tag__prefix">#</span><%= tag %></span>
<% end %>
</div>
</a>
<% end %>
</div>
</div>
<% elsif @sticky_articles.present? %>
<div class="crayons-card crayons-card--secondary">
<header class="crayons-card__header">
<h3 class="crayons-card__header__headline">
Trending on <a href="<%= app_url %>"><%= community_name %></a>
<%= inline_svg_tag("twemoji/fire.svg", aria: true, class: "crayons-icon crayons-icon--default", title: "Hot") %>
</h3>
</header>
<div>
<% @sticky_articles.each_with_index do |article, index| %>
<a class="crayons-link crayons-link--contentful flex" href="<%= article.path %>">
<span class="crayons-avatar mr-2 shrink-0">
<img src="<%= ProfileImage.new(article.user).get(width: 90) %>" class="crayons-avatar__image" loading="lazy" alt="<%= article.user.name %> profile image">
</span>
<div>
<%= article.title %>
<div class="crayons-link__secondary -ml-1">
<% article.decorate.cached_tag_list_array.each do |tag| %>
<span class="crayons-tag"><span class="crayons-tag__prefix">#</span><%= tag %></span>
<% end %>
</div>
</div>
</a>
<% end %>
</div>
</div>
<% end %>
</div>
<% cache("article-sticky-nav-articles-#{@article.id}-#{@actor.last_article_at}", expires_in: 48.hours) do %>
<% @sticky_collection = StickyArticleCollection.new(@article, @organization || @user) %>
<% @sticky_articles = @sticky_collection.suggested_stickies %>
<% @user_stickies = @sticky_collection.user_stickies %>
<% if @user_stickies.any? %>
<% @user_stickies.each_with_index do |article, index| %>
<div class="primary-sticky-nav-element-wrapper">
<% if index == 0 %>
<div class="primary-sticky-nav-title">
<% if @actor.username.size < 18 %>
More from <a href="<%= @actor.path %>">@<%= @actor.username %></a>
<% else %>
More from<br /><a href="<%= @actor.path %>">@<%= @actor.username %></a>
<% end %>
</div>
<% end %>
<a class="primary-sticky-nav-element primary-sticky-nav-author-element" href="<%= article.path %>">
<img src="<%= ProfileImage.new(article.user).get(width: 90) %>" class="primary-sticky-nav-profile-image" loading="lazy" alt="<%= article.user.name %> profile image">
<%= article.title %>
<div class="primary-sticky-nav-element-details">
<% article.decorate.cached_tag_list_array.each do |tag| %>
<span>#<%= tag %></span>
<% end %>
</div>
</a>
</div>
<% end %>
<% end %>
<% if @sticky_articles %>
<% @sticky_articles.each_with_index do |article, index| %>
<div class="primary-sticky-nav-element-wrapper">
<% if index == 0 %>
<div class="primary-sticky-nav-title">
<img src="<%= asset_path "emoji/apple-fire.png" %>" alt="Fire emoji" loading="lazy"> Trending on <a href="<%= app_url %>"><%= community_name %></a>
</div>
<% end %>
<a class="primary-sticky-nav-element" href="<%= article.path %>">
<img src="<%= ProfileImage.new(article.user).get(width: 90) %>" class="primary-sticky-nav-profile-image" loading="lazy" alt="<%= article.user.name %> profile image">
<%= article.title %>
<div class="primary-sticky-nav-element-details">
<% article.decorate.cached_tag_list_array.each do |tag| %>
<span>#<%= tag %></span>
<% end %>
</div>
</a>
</div>
<% end %>
<% end %>
<% end %>
</div>

View file

@ -1,75 +1,57 @@
<%# <style>
.user-metadata-details-inner a {
color: var(--body-color);
}
</style> %>
<div class="user-metadata-details">
<div class="user-metadata-details-inner">
<% if @organization %>
<% if @organization.location.present? %>
<div class="row">
<div class="key">
headquarters
</div>
<div class="value">
<%= sanitize @organization.location %>
</div>
</div>
<% end %>
<% if @organization.company_size.present? %>
<div class="row">
<div class="key">
employees
</div>
<div class="value">
<%= @organization.company_size %>
</div>
</div>
<% end %>
<% if @organization.email.present? %>
<div class="row">
<div class="key">
support_email
</div>
<div class="value">
<a href="mailto:<%= sanitize @organization.email %>"><%= sanitize @organization.email %></a>
</div>
</div>
<% end %>
<% else %>
<ul class="user-metadata-details-inner">
<% if @organization %>
<% if @organization.location.present? %>
<li>
<div class="key">
Headquarters
</div>
<div class="value">
<%= sanitize @organization.location %>
</div>
</li>
<% end %>
<% if @organization.company_size.present? %>
<li>
<div class="key">
Employees
</div>
<div class="value">
<%= @organization.company_size %>
</div>
</li>
<% end %>
<% if @organization.email.present? %>
<li>
<div class="key">
Support email
</div>
<div class="value">
<a href="mailto:<%= sanitize @organization.email %>"><%= sanitize @organization.email %></a>
</div>
</li>
<% end %>
<% else %>
<% if @user.email_public &&
@user.employer_name.present? &&
@user.location.present? &&
@user.education.present? &&
@user.education.size > 25 &&
@user.summary.to_s.size < 145 %>
<style>
.user-profile-header {
min-height: 398px;
}
</style>
<% end %>
<% if @user.email_public && context != "sidebar" %>
<div class="row">
<li>
<div class="key">
email
Email
</div>
<div class="value">
<a href="mailto:<%= @user.email %>"><%= @user.email %></a>
</div>
</div>
</li>
<% end %>
<% if @user.employment_title.present? %>
<div class="row">
<li>
<div class="key">
work
Work
</div>
<div class="value">
<span><%= @user.employment_title %></span>
<%= @user.employment_title %>
<% if @user.employer_name.present? %>
<span> at </span>
<span class="opacity-50"> at </span>
<% if @user.employer_url.present? %>
<a href="<%= @user.employer_url %>" target="_blank" rel="noopener"><%= @user.employer_name %></a>
<% else %>
@ -77,46 +59,46 @@
<% end %>
<% end %>
</div>
</div>
</li>
<% end %>
<% if @user.location.present? %>
<div class="row">
<li>
<div class="key">
location
Location
</div>
<div class="value">
<%= @user.location %>
</div>
</div>
</li>
<% end %>
<% if @user.looking_for_work_publicly == true && @user.looking_for_work == true %>
<div class="row">
<li>
<div class="key">
work_status
Work status
</div>
<div class="value">
I'm looking for work!
</div>
</div>
</li>
<% end %>
<% if @user.education.present? %>
<div class="row">
<li>
<div class="key">
education
Education
</div>
<div class="value">
<ul class="value">
<%= @user.education %>
</div>
</div>
</ul>
</li>
<% end %>
<% end %>
<div class="row">
<li>
<div class="key">
joined
Joined
</div>
<div class="value">
<%= @user.created_at.strftime("%b %e, %Y") %>
</div>
</div>
</div>
</li>
</ul>
</div>

View file

@ -45,7 +45,7 @@
<div class="crayons-card crayons-article-form__content">
<% if version == "v2" %>
<div>
<div class="text-padding">
<div class="crayons-article-form__cover" role="presentation">
<% if article.main_image.present? %>
<img src="<%= article.main_image %>" width="250" height="105" alt="Post cover" class="crayons-article-form__cover__image">
@ -65,7 +65,7 @@
</div>
</div>
<% end %>
<div class="crayons-article-form__body">
<div class="crayons-article-form__body text-padding">
<div class="crayons-article-form__toolbar">
<button class="crayons-btn crayons-btn--ghost crayons-btn--icon-left fw-normal" type="button">
<%= (inline_svg_tag("image.svg", aria: true, class: "crayons-icon", title: "Image") + "Upload image").delete!("\n").html_safe %>
@ -75,6 +75,7 @@
<textarea class="crayons-article-form__body__field crayons-textfield crayons-textfield--ghost" id="article_body_markdown" placeholder="Write your post content here..." name="body_markdown"><%= article.body_markdown %></textarea>
</div>
</div>
<div class="crayons-article-form__aside"></div>
<div class="crayons-article-form__aside"></div>

View file

@ -1,8 +1,8 @@
<div class="video-player-header">
<div class="crayons-article__video">
<% minutes, seconds = article.video_duration_in_minutes.split(":") %>
<div id="video-player-source" data-source="<%= article.video_source_url %>"></div>
<script src="//content.jwplatform.com/libraries/b1zWy2iv.js" async></script>
<div id="video-player-<%= article.id %>" class="video-player"></div>
<div id="video-player-<%= article.id %>" class="crayons-article__video__player"></div>
<% unless internal_navigation? || user_signed_in? %>
<script type="application/ld+json">
{

View file

@ -81,96 +81,102 @@
<% end %>
<% end %>
<div class="home">
<div
class="container article"
id="article-show-container"
data-author-id="<%= @article.user_id %>"
data-path="<%= @article.path %>"
data-published="<%= @article.published? %>">
<% if @article.video_state == "PROGRESSING" %>
<h1 style="text-align:center;">⏳ Video Transcoding In Progress ⏳</h1>
<% has_long_markdown = @article.body_markdown && @article.body_markdown.size > 900 %>
<div class="crayons-layout crayons-layout--3-cols crayons-layout--article">
<div class="crayons-layout__sidebar-left">
<%= render "articles/actions" %>
</div>
<div class="crayons-layout__content grid gap-4">
<% if !@article.published %>
<div class="crayons-notice crayons-notice--danger">
<strong>Unpublished Post.</strong> This URL is public but secret, so share at your own discretion.
<a href="<%= @article.path %>/edit" class="fw-bold">Click to edit</a>.
</div>
<% end %>
<article>
<section>
<% if !@article.published %>
<a href="<%= @article.path %>/edit" class="unpublished">
Unpublished Post. This URL is public but secret, so share at your own discretion.
<em style="display: inline-block;">Click to edit.</em>
</a>
<% end %>
<% if @article.video_state == "PROGRESSING" %>
<div class="crayons-notice crayons-notice--warning">⏳ Video Transcoding In Progress ⏳</div>
<% end %>
<article class="crayons-card crayons-article"
id="article-show-container"
data-author-id="<%= @article.user_id %>"
data-path="<%= @article.path %>"
data-published="<%= @article.published? %>">
<header class="crayons-article__header" id="main-title">
<% if @article.video.present? %>
<%= render "articles/video_player", meta_tags: true, article: @article %>
<% elsif @article.main_image.present? %>
<img src="<%= cloud_cover_url(@article.main_image) %>" class="image image-final" style="background-color:<%= @article.main_image_background_hex_color %>;" alt="Cover image for <%= @article.title %>" />
<% else %>
<div class="blank-space"></div>
<% end %>
</section>
<header class="title" id="main-title">
<% if @organization %>
<a href="<%= @organization.path %>" class="org-branded-title-link">
<div class="org-branded-title">
<img src="<%= ProfileImage.new(@organization).get(width: 50) %>" class="org-pic" alt="<%= @organization.name %> profile image"> <%= @organization.name %>
</div>
</a>
<% end %>
<h1 class="<%= @article.title_length_classification %>">
<% if @article.search_optimized_title_preamble.present? && !user_signed_in? %>
<span class="article-title-preamble"><%= @article.search_optimized_title_preamble %></span>
<% end %>
<%= sanitize_and_decode @article.title %>
</h1>
<h3>
<span>
<a href="/<%= @user.username %>" class="author">
<img class="profile-pic" src="<%= ProfileImage.new(@user).get(width: 50) %>" alt="<%= @user.username %> profile image" />
<span><%= @user.name %></span>
</a>
</span>
<% if @user.twitter_username.present? %>
<a href="http://twitter.com/<%= @user.twitter_username %>"><%= image_tag_or_inline_svg_tag "twitter", width: 18, height: 18 %></a>
<% end %>
<% if @user.github_username.present? %>
<a href="http://github.com/<%= @user.github_username %>"><%= image_tag_or_inline_svg_tag "github", width: 18, height: 18 %></a>
<% end %>
<% if @article.published_timestamp.present? %>
<time datetime="<%= @article.published_timestamp %>"><%= @article.readable_publish_date %></time>
<% end %>
<% if @second_user.present? %>
<em>with <b><a href="<%= @second_user.path %>"><%= @second_user.name %></a></b></em>
<% end %>
<% if @third_user.present? %>
<em> and <b><a href="<%= @third_user.path %>"><%= @third_user.name %></a></b></em>
<% end %>
<% if should_show_updated_on?(@article) %>
<span><em>Updated on <time datetime="<%= @article.edited_at&.utc&.iso8601 %>"><%= @article.edited_at&.strftime("%b %d, %Y") %></time></em></span>
<% elsif should_show_crossposted_on?(@article) %>
<span>
<em>
Originally published at
<a href="<%= @article.canonical_url || @article.feed_source_url %>" style="color:#1395b8"><%= get_host_without_www(@article.canonical_url || @article.feed_source_url) %></a>
on
<% if @article.crossposted_at %>
<time datetime="<%= (@article.originally_published_at || @article.published_at)&.utc&.iso8601 %>"><%= (@article.originally_published_at || @article.published_at)&.strftime("%b %d, %Y") %></time>
<% end %>
</em>
</span>
<% end %>
<span class="published-at">・<%= @article.reading_time < 1 ? 1 : @article.reading_time %> min read</span>
<% if user_signed_in? %>
<span class="action-space" id="action-space">&nbsp;</span>
<% end %>
</h3>
<% cache("main-article-tags-#{@article.cached_tag_list}", expires_in: 30.hours) do %>
<div class="tags">
<% @article.cached_tag_list_array.each do |tag| %>
<% tag_hash = tag_colors(tag) %>
<a class="tag" href="/t/<%= tag %>" style="background-color:<%= tag_hash[:background] %>;color:<%= tag_hash[:color] %>">#<%= tag %></a>
<% end %>
<div class="crayons-article__cover">
<img src="<%= cloud_cover_url(@article.main_image) %>" width="1000" height="420" style="background-color:<%= @article.main_image_background_hex_color %>;" class="crayons-article__cover__image" alt="Cover image for <%= sanitize_and_decode @article.title %>">
</div>
<% end %>
<div class="crayons-article__header__meta">
<% if @organization %>
<a href="<%= @organization.path %>" class="flex items-center mb-4 fs-l fw-medium crayons-link">
<span class="crayons-logo crayons-logo--l mr-3">
<img src="<%= ProfileImage.new(@organization).get(width: 50) %>" class="crayons-logo__image" alt="<%= @organization.name %> profile image">
</span>
<%= @organization.name %>
</a>
<% end %>
<h1 class="fs-3xl s:fs-4xl l:fs-5xl fw-bold s:fw-heavy lh-tight mb-4 <%= @article.title_length_classification %>">
<% if @article.search_optimized_title_preamble.present? && !user_signed_in? %>
<span class="article-title-preamble"><%= @article.search_optimized_title_preamble %></span>
<% end %>
<%= sanitize_and_decode @article.title %>
</h1>
<% cache("main-article-tags-#{@article.cached_tag_list}", expires_in: 30.hours) do %>
<div class="mb-4 spec__tags">
<% @article.cached_tag_list_array.each do |tag| %>
<% tag_hash = tag_colors(tag) %>
<a class="crayons-tag mr-1" href="/t/<%= tag %>" style="background-color:<%= tag_hash[:background] %>;color:<%= tag_hash[:color] %>"><span class="crayons-tag__prefix">#</span><%= tag %></a>
<% end %>
</div>
<% end %>
<div class="crayons-article__subheader">
<a href="/<%= @user.username %>" class="flex items-center mr-4 fw-medium crayons-link">
<span class="crayons-avatar crayons-avatar--l mr-2"><img class="crayons-avatar__image" src="<%= ProfileImage.new(@user).get(width: 50) %>" alt="<%= @user.username %> profile image" /></span>
<%= @user.name %>
</a>
<span class="fs-s">
<% if @article.published_timestamp.present? %>
<time datetime="<%= @article.published_timestamp %>"><%= @article.readable_publish_date %></time>
<% end %>
<% if @second_user.present? %>
<em>with <b><a href="<%= @second_user.path %>"><%= @second_user.name %></a></b></em>
<% end %>
<% if @third_user.present? %>
<em> and <b><a href="<%= @third_user.path %>"><%= @third_user.name %></a></b></em>
<% end %>
<% if should_show_updated_on?(@article) %>
<em>Updated on <time datetime="<%= @article.edited_at&.utc&.iso8601 %>"><%= @article.edited_at&.strftime("%b %d, %Y") %></time></em>
<% elsif should_show_crossposted_on?(@article) %>
<em>
Originally published at
<a href="<%= @article.canonical_url || @article.feed_source_url %>" style="color:#1395b8"><%= get_host_without_www(@article.canonical_url || @article.feed_source_url) %></a>
on
<% if @article.crossposted_at %>
<time datetime="<%= (@article.originally_published_at || @article.published_at)&.utc&.iso8601 %>"><%= (@article.originally_published_at || @article.published_at)&.strftime("%b %d, %Y") %></time>
<% end %>
</em>
<% end %>
<span class="mr-2">・<%= @article.reading_time < 1 ? 1 : @article.reading_time %> min read</span>
</span>
<span id="action-space"></span>
</div>
</div>
</header>
<% if @collection %>
<%= render "articles/collection",
rendered_article: @article,
@ -178,45 +184,55 @@
articles: @collection_articles,
position: :top %>
<% end %>
<div class="body" data-article-id="<%= @article.id %>" id="article-body">
<div class="crayons-article__body spec__body" data-article-id="<%= @article.id %>" id="article-body">
<%= @article.processed_html.html_safe %>
</div>
<% if @article.body_markdown && @article.body_markdown.size > 900 && @collection %>
<% if has_long_markdown && @collection %>
<%= render "articles/collection",
rendered_article: @article,
collection: @collection,
articles: @collection_articles,
position: :bottom %>
<% end %>
<%= render "articles/actions" %>
</article>
<% if @article.body_markdown && @article.body_markdown.size > 900 %>
<% cache("article-about-author-#{@user.id}-#{@user.updated_at}", expires_in: 100.hours) do %>
<%= render "articles/about_author" %>
<% end %>
<% end %>
<%= render "articles/org_branding", organization: @organization %>
<%= render "articles/full_comment_area" %>
</div>
<% cache("article-bottom-content-#{@article.id}", expires_in: 18.hours) do %>
<% @classic_article = Suggester::Articles::Classic.new(@article, not_ids: [@article.id]).get.first %>
<% if @classic_article %>
<%= render "additional_content_boxes/article_box",
article: @classic_article,
classification: "classic",
classification_text: "Classic #{community_name} Post from #{@classic_article.readable_publish_date}",
follow_cue: "Follow <a href='#{@classic_article.user.path}'>@#{@classic_article.user.username}</a> to see more of their posts in your feed." %>
<% end %>
<div id="additional-content-area" data-article-id="<%= @article.id %>,<%= @classic_article&.id %>"></div>
<% suggested_articles = ArticleSuggester.new(@article).articles(max: 4) %>
<%= render "articles/bottom_content", articles: suggested_articles %>
<% end %>
</div>
<% stick_nav_cache_key = "sticky-sidebar-#{@article.id}-#{(@organization || @user).profile_updated_at}-#{(@organization || @user).last_article_at}-0-#{@user.pro?}" %>
<% cache(stick_nav_cache_key, expires_in: 50.hours) do %>
<%= render "articles/sticky_nav" %>
<% end %>
<% if has_long_markdown || @organization %>
<section class="crayons-card crayons-card--secondary text-padding">
<% if has_long_markdown %>
<% cache("article-about-author-#{@user.id}-#{@user.updated_at}", expires_in: 100.hours) do %>
<%= render "articles/about_author", published: @article.readable_publish_date %>
<% end %>
<% end %>
<%= render "articles/org_branding", organization: @organization, author: has_long_markdown %>
</section>
<% end %>
<%= render "articles/full_comment_area" %>
<% cache("article-bottom-content-#{@article.id}", expires_in: 18.hours) do %>
<% @classic_article = Suggester::Articles::Classic.new(@article, not_ids: [@article.id]).get.first %>
<% if @classic_article %>
<%= render "additional_content_boxes/article_box",
article: @classic_article,
classification: "classic",
classification_text: "Classic #{community_name} Post from #{@classic_article.readable_publish_date}",
follow_cue: "Follow <a href='#{@classic_article.user.path}'>@#{@classic_article.user.username}</a> to see more of their posts in your feed." %>
<% end %>
<aside id="additional-content-area" class="gap-4" data-article-id="<%= @article.id %>,<%= @classic_article&.id %>"></aside>
<% suggested_articles = ArticleSuggester.new(@article).articles(max: 4) %>
<%= render "articles/bottom_content", articles: suggested_articles %>
<% end %>
</div>
<div class="crayons-layout__sidebar-right">
<% stick_nav_cache_key = "sticky-sidebar-#{@article.id}-#{(@organization || @user).profile_updated_at}-#{(@organization || @user).last_article_at}-1-#{@user.pro?}" %>
<% cache(stick_nav_cache_key, expires_in: 50.hours) do %>
<%= render "articles/sticky_nav" %>
<% end %>
</aside>
</div>
<% cache("specific-article-extra-scripts-#{@article.id}-#{@article.updated_at}", expires_in: 24.hours) do %>
<% if has_vid?(@article) %>

View file

@ -57,11 +57,9 @@
<%= image_tag("three-dots.svg", class: "dropdown-icon", alt: "Dropdown menu") %>
</button>
<div class="dropdown">
<div class="dropdown-content">
<a href="<%= comment.path %>">
Permalink
</a>
<span class="comment-actions hidden" data-user-id="<%= comment.user_id %>" style="display: none;" data-action="settings-button" data-path="<%= comment.path %>/settings">
<div class="crayons-dropdown p-1 z-30 right-1 left-1 s:right-0 s:left-auto fs-base">
<a href="<%= comment.path %>" class="crayons-link crayons-link--block">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%;">
@ -69,9 +67,8 @@
<%= action %>
</button>
</span>
<span class="mod-actions hidden mod-actions-comment-button" style="display: none;" data-path="<%= comment.path %>/mod">
</span>
<a href="/report-abuse?url=<%= comment_url(comment) %>">Report Abuse</a>
<span class="mod-actions hidden mod-actions-comment-button" data-path="<%= comment.path %>/mod"></span>
<a href="/report-abuse?url=<%= comment_url(comment) %>" class="crayons-link crayons-link--block">Report Abuse</a>
</div>
</div>
</div>

View file

@ -1,5 +1,5 @@
<footer>
<div id="footer-container" class="container <%= "centered-footer" unless current_page.include?("stories-show") %>">
<footer class="clear">
<div id="footer-container" class="clear container <%= "centered-footer" unless current_page.include?("stories-show") %>">
<div class="inner-footer-container">
<a href="/">Home</a> <a href="/about">About</a> <a href="/privacy">Privacy Policy</a>
<a href="/terms">Terms of Use</a> <a href="/contact">Contact</a> <a href="/code-of-conduct">Code of Conduct</a><br />

View file

@ -32,14 +32,14 @@ RSpec.describe "articles/show", type: :view do
it "shows user tags" do
render
expect(rendered).to have_css "div.tags"
expect(rendered).to have_css ".spec__tags"
article1.tags.all? { |tag| expect(rendered).to have_text(tag.name) }
end
it "shows user content of the article" do
render
expect(rendered).to have_text(Nokogiri::HTML(article1.processed_html).text)
expect(rendered).to have_css "div.body"
expect(rendered).to have_css ".spec__body"
end
it "shows user new comment box" do