* Revert "[deploy] Revert removal of unneeded eager load (if needed) (#10179)" This reverts commit11c7b148da. * Revert "[deploy] Revert "Migrate ProfileImage to Images::Profile (#10055)" (#10149)" This reverts commit5657067e55.
258 lines
12 KiB
Text
258 lines
12 KiB
Text
<% title @article.title_with_query_preamble(user_signed_in?) %>
|
|
|
|
<%= render "shared/payment_pointer", user: @article.user %>
|
|
|
|
<style>
|
|
.html-variant-wrapper { display: none}
|
|
</style>
|
|
|
|
<%= render "shared/webcomponents_loader_script" %>
|
|
<% if user_signed_in? %>
|
|
<%= javascript_packs_with_chunks_tag "clipboardCopy", "webShare", "articlePage", "articleModerationTools", defer: true %>
|
|
<% else %>
|
|
<%= javascript_packs_with_chunks_tag "clipboardCopy", "webShare", "articlePage", defer: true %>
|
|
<% end %>
|
|
|
|
<% cache("content-related-optional-scripts-#{@article.id}-#{@article.updated_at}-#{internal_navigation?}-#{user_signed_in?}", expires_in: 30.hours) do %>
|
|
<% if @article.processed_html.include? "ltag_gist-liquid-tag" %>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/postscribe/2.0.8/postscribe.min.js"
|
|
integrity="sha256-xOIPU/XvDtRLeDQ3qj9GOKmlbMSqKa6D7ZIS6ygHBSo="
|
|
crossorigin="anonymous" defer></script>
|
|
<script defer>
|
|
var waitingOnPostscribe = setInterval(function () {
|
|
if (typeof (postscribe) === "function") {
|
|
clearInterval(waitingOnPostscribe);
|
|
var els = document.getElementsByClassName("ltag_gist-liquid-tag");
|
|
for (var i = 0; i < els.length; i++) {
|
|
let current = els[i];
|
|
postscribe(current, current.firstElementChild.outerHTML, {
|
|
beforeWrite: function (context) {
|
|
return function (text) {
|
|
if (context.childElementCount > 3) {
|
|
return "";
|
|
}
|
|
return text;
|
|
}
|
|
}(current)
|
|
});
|
|
}
|
|
}
|
|
}, 500)
|
|
</script>
|
|
<% end %>
|
|
<% unless internal_navigation? || user_signed_in? %>
|
|
<script type="application/ld+json">
|
|
<%= @article_json_ld.to_json.html_safe %>
|
|
</script>
|
|
<% end %>
|
|
<% end %>
|
|
|
|
<% if internal_navigation? %>
|
|
<link rel="canonical" href="<%= @article.canonical_url.presence || app_url(@article.path) %>" />
|
|
<meta name="description" content="<%= @article.description_and_tags %>">
|
|
<meta name="keywords" content="<%= @article.cached_tag_list %>, <%= SiteConfig.meta_keywords[:article] %>">
|
|
<% else %>
|
|
<%= content_for :page_meta do %>
|
|
<link rel="canonical" href="<%= @article.canonical_url.presence || app_url(@article.path) %>" />
|
|
<meta name="description" content="<%= @article.description_and_tags %>">
|
|
<meta name="keywords" content="<%= @article.cached_tag_list %>, <%= SiteConfig.meta_keywords[:article] %>">
|
|
|
|
<meta property="og:type" content="article" />
|
|
<meta property="og:url" content="<%= article_url(@article) %>" />
|
|
<meta property="og:title" content="<%= @article.title %>" />
|
|
<meta property="og:description" content="<%= @article.description || "An article from the community" %>" />
|
|
<meta property="og:site_name" content="<%= community_qualified_name %>" />
|
|
<meta name="twitter:site" content="@<%= SiteConfig.social_media_handles["twitter"] %>">
|
|
<meta name="twitter:creator" content="@<%= @user.twitter_username %>">
|
|
<meta name="twitter:title" content="<%= @article.title %>">
|
|
<meta name="twitter:description" content="<%= @article.description || "An article from the community" %>">
|
|
<meta name="twitter:card" content="summary_large_image">
|
|
<meta name="twitter:widgets:new-embed-design" content="on">
|
|
<meta name="robots" content="max-snippet:-1, max-image-preview:large, max-video-preview:-1">
|
|
<% if @article.published %>
|
|
<meta property="og:image" content="<%= article_social_image_url(@article) %>" />
|
|
<meta name="twitter:image:src" content="<%= article_social_image_url(@article) %>">
|
|
<% end %>
|
|
<% if !@article.published ||
|
|
(@article.score < 5 &&
|
|
@article.user.comments_count < 1 &&
|
|
!@article.featured &&
|
|
@article.processed_html.exclude?("<code>")) ||
|
|
@article.featured_number.to_i < 1500000000 ||
|
|
@article.score < -1 %>
|
|
<meta name="googlebot" content="noindex">
|
|
<meta name="googlebot" content="nofollow">
|
|
<% end %>
|
|
<% end %>
|
|
<% end %>
|
|
|
|
<div class="crayons-layout crayons-layout--3-cols crayons-layout--article">
|
|
<aside class="crayons-layout__sidebar-left" aria-label="Article actions">
|
|
<%= render "articles/actions" %>
|
|
</aside>
|
|
|
|
<main class="crayons-layout__content grid gap-4">
|
|
<div class="article-wrapper">
|
|
<% if !@article.published %>
|
|
<div class="crayons-notice crayons-notice--danger mb-4">
|
|
<strong>Unpublished Post.</strong> This URL is public but secret, so share at your own discretion.
|
|
<% if user_signed_in? && policy(@article.object).update? %>
|
|
<a href="<%= @article.path %>/edit" class="fw-bold">Click to edit</a>.
|
|
<% end %>
|
|
</div>
|
|
<% end %>
|
|
|
|
<% if @article.video_state == "PROGRESSING" %>
|
|
<div class="crayons-notice crayons-notice--warning mb-4">⏳ Video Transcoding In Progress ⏳</div>
|
|
<% end %>
|
|
|
|
<article class="crayons-card crayons-article mb-4"
|
|
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? %>
|
|
<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="<%= Images::Profile.call(@organization.profile_image_url, length: 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="fs-xl color-base-70 block"><%= @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 mb-4 s:mb-0 fw-medium crayons-link">
|
|
<span class="crayons-avatar crayons-avatar--l mr-2"><img class="crayons-avatar__image" src="<%= Images::Profile.call(@user.profile_image_url, length: 50) %>" alt="<%= @user.username %> profile image" /></span>
|
|
<%= @user.name %>
|
|
</a>
|
|
|
|
<span class="fs-s mb-4 s:mb-0">
|
|
<% if @article.published_timestamp.present? %>
|
|
<%= local_date(@article.published_timestamp, show_year: @article.displayable_published_at.year != Time.current.year) %>
|
|
<% 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>
|
|
<% if @article.crossposted_at %>
|
|
on
|
|
<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-4">・<%= @article.reading_time < 1 ? 1 : @article.reading_time %> min read</span>
|
|
</span>
|
|
<span id="action-space" class="mb-4 s:mb-0"></span>
|
|
</div>
|
|
|
|
</div>
|
|
</header>
|
|
|
|
<div class="crayons-article__main">
|
|
<% if @collection %>
|
|
<%= render "articles/collection",
|
|
rendered_article: @article,
|
|
collection: @collection,
|
|
articles: @collection_articles %>
|
|
<% end %>
|
|
|
|
<div class="crayons-article__body text-styles spec__body" data-article-id="<%= @article.id %>" id="article-body">
|
|
<%= @article.processed_html.html_safe %>
|
|
</div>
|
|
|
|
<% if @article.long_markdown? && @collection %>
|
|
<%= render "articles/collection",
|
|
rendered_article: @article,
|
|
collection: @collection,
|
|
articles: @collection_articles %>
|
|
<% end %>
|
|
</div>
|
|
</article>
|
|
|
|
<% if @article.long_markdown? || @organization %>
|
|
<section class="crayons-card crayons-card--secondary text-padding mb-4">
|
|
<% if @article.long_markdown? %>
|
|
<%= render "articles/about_author", published: @article.readable_publish_date %>
|
|
<% end %>
|
|
<%= render "articles/org_branding", organization: @organization, author: @article.long_markdown? %>
|
|
</section>
|
|
<% end %>
|
|
|
|
<%= render "articles/full_comment_area" %>
|
|
|
|
<% cache("article-bottom-content-#{@article.id}-#{user_signed_in?}", expires_in: 18.hours) do %>
|
|
<% suggested_articles = ArticleSuggester.new(@article).articles(max: 4) %>
|
|
<%= render "articles/bottom_content", articles: suggested_articles %>
|
|
<% end %>
|
|
</div>
|
|
</main>
|
|
|
|
<aside class="crayons-layout__sidebar-right" aria-label="Right sidebar navigation">
|
|
<% 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) %>
|
|
<%= render "articles/fitvids" %>
|
|
<% end %>
|
|
<% if @article.processed_html.include? 'class="twitter-tweet"' %>
|
|
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
|
|
<% end %>
|
|
<% if @article.processed_html.include? "instagram-media" %>
|
|
<script async defer src="//platform.instagram.com/en_US/embeds.js"></script>
|
|
<% end %>
|
|
<% end %>
|
|
|
|
<div class="mod-actions-menu"></div>
|
|
<div id="mod-actions-menu-btn-area"></div>
|
|
<div data-testid="flag-user-modal-container" class="flag-user-modal-container hidden"></div>
|
|
|
|
<% cache("article-show-scripts", expires_in: 8.hours) do %>
|
|
<script async>
|
|
<%# we consider these scripts safe for embedding as they come from our code %>
|
|
<%== PodcastTag.script %>
|
|
<%== PollTag.script %>
|
|
<%== RunkitTag.script %>
|
|
<%== TweetTag.script %>
|
|
<%== UserSubscriptionTag.script %>
|
|
</script>
|
|
<% end %>
|