196 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| @use plume_models::blogs::Blog;
 | |
| @use plume_models::comments::{Comment, CommentTree};
 | |
| @use plume_models::posts::Post;
 | |
| @use plume_models::tags::Tag;
 | |
| @use plume_models::users::User;
 | |
| @use std::path::Path;
 | |
| @use validator::ValidationErrors;
 | |
| @use crate::templates::{base, partials::comment};
 | |
| @use crate::template_utils::*;
 | |
| @use crate::routes::comments::NewCommentForm;
 | |
| @use crate::routes::*;
 | |
| 
 | |
| @(ctx: BaseContext, article: Post, blog: Blog, comment_form: &NewCommentForm, comment_errors: ValidationErrors, tags: Vec<Tag>, comments: Vec<CommentTree>, previous_comment: Option<Comment>, n_likes: i64, n_reshares: i64, has_liked: bool, has_reshared: bool, is_following: bool, author: User)
 | |
| 
 | |
| @:base(ctx, article.title.clone(), {
 | |
|     <meta property="og:title" content="@article.title"/>
 | |
|     <meta property="og:type" content="article"/>
 | |
|     @if article.cover_id.is_some() {
 | |
|         <meta property="og:image" content="@Html(article.cover_url(ctx.0).unwrap_or_default())"/>
 | |
|     }
 | |
|     <meta property="og:url" content="@uri!(posts::details: blog = &blog.fqn, slug = &article.slug, responding_to = _)"/>
 | |
|     <meta property="og:description" content="@article.subtitle"/>
 | |
|     <link rel="canonical" href="@article.ap_url"/>
 | |
| 
 | |
|     @if !ctx.2.clone().map(|u| u.hide_custom_css).unwrap_or(false) {
 | |
|         @if let Some(ref theme) = blog.theme {
 | |
|             <link rel="stylesheet" href="@uri!(plume_static_files: file = Path::new("css").join(theme).join("theme.css"), build_id = CACHE_NAME)">
 | |
|         }
 | |
|     }
 | |
| }, {
 | |
|     <a href="@uri!(blogs::details: name = &blog.fqn, page = _)">@blog.title</a>
 | |
| }, {
 | |
| <div class="h-entry">
 | |
|     <header
 | |
|         class="article @if article.cover_id.is_some() { illustrated }"
 | |
|         @if article.cover_id.is_some() { style="background-image: url('@article.cover_url(ctx.0).unwrap_or_default()'" }
 | |
|     >
 | |
|         <div>
 | |
|             <h1 class="article p-name" dir="auto">@article.title</h1>
 | |
|             <div class="article-info" dir="auto">
 | |
|                 <span class="author">
 | |
|                     @Html(i18n!(ctx.1, "Written by {0}"; format!("<a href=\"{}\">{}</a>",
 | |
|                                         escape(&uri!(user::details: name = &author.fqn).to_string()),
 | |
|                                         escape(&author.name()))))
 | |
|                 </span>
 | |
|                 —
 | |
|                 <span class="date dt-published" datetime="@article.creation_date.format("%F %T")">@article.creation_date.format("%B %e, %Y")</span><a class="u-url" href="@article.ap_url"></a>
 | |
|             </div>
 | |
|             <h2 class="article p-summary" dir="auto">@article.subtitle</h2>
 | |
|         </div>
 | |
|         @if article.cover_id.is_some() {
 | |
|             <div class="shadow"></div>
 | |
|             <img class="u-photo hidden" src="@article.cover_url(ctx.0).unwrap_or_default()"/>
 | |
|         }
 | |
|     </header>
 | |
| 
 | |
|     <article class="e-content" dir="auto">
 | |
|         @Html(&article.content)
 | |
|     </article>
 | |
|     <div class="article-meta">
 | |
|         <section class="split">
 | |
|             <ul class="tags" dir="auto">
 | |
|                 @for tag in tags {
 | |
|                     @if !tag.is_hashtag {
 | |
|                         <li><a class="p-category" href="@uri!(tags::tag: name = &tag.tag, page = _)">@tag.tag</a></li>
 | |
|                     } else {
 | |
|                         <span class="hidden p-category">@tag.tag</span>
 | |
|                     }
 | |
|                 }
 | |
|             </ul>
 | |
|             <p class="right" dir="auto">
 | |
|                 @if article.license.is_empty() {
 | |
|                     @i18n!(ctx.1, "All rights reserved."; &article.license)
 | |
|                 } else {
 | |
|                     @i18n!(ctx.1, "This article is under the {0} license."; &article.license)
 | |
|                 }
 | |
|             </p>
 | |
|         </section>
 | |
|         @if ctx.2.is_some() {
 | |
|             <section class="actions">
 | |
|                 <form class="likes" action="@uri!(likes::create: blog = &blog.fqn, slug = &article.slug)" method="POST">
 | |
|                     <p aria-label="@i18n!(ctx.1, "One like", "{0} likes"; n_likes)" title="@i18n!(ctx.1, "One like", "{0} likes"; n_likes)">
 | |
|                         @n_likes
 | |
|                     </p>
 | |
| 
 | |
|                     @if has_liked {
 | |
|                         <button type="submit" class="action liked">@icon!("heart") @i18n!(ctx.1, "I don't like this anymore")</button>
 | |
|                     } else {
 | |
|                         <button type="submit" class="action">@icon!("heart") @i18n!(ctx.1, "Add yours")</button>
 | |
|                     }
 | |
|                 </form>
 | |
|                 <form class="reshares" action="@uri!(reshares::create: blog = &blog.fqn, slug = &article.slug)" method="POST">
 | |
|                     <p aria-label="@i18n!(ctx.1, "One boost", "{0} boosts"; n_reshares)" title="@i18n!(ctx.1, "One boost", "{0} boosts"; n_reshares)">
 | |
|                         @n_reshares
 | |
|                     </p>
 | |
| 
 | |
|                     @if has_reshared {
 | |
|                         <button type="submit" class="action reshared">@icon!("repeat") @i18n!(ctx.1, "I don't want to boost this anymore")</button>
 | |
|                     } else {
 | |
|                         <button type="submit" class="action">@icon!("repeat") @i18n!(ctx.1, "Boost")</button>
 | |
|                     }
 | |
|                 </form>
 | |
|             </section>
 | |
|         } else {
 | |
|             <p class="center">@Html(i18n!(ctx.1, "{0}Log in{1}, or {2}use your Fediverse account{3} to interact with this article";
 | |
|                 format!("<a href='{}'>", escape(&uri!(session::new: m = _).to_string())), "</a>",
 | |
|                 format!("<a href='{}'>", escape(&uri!(posts::remote_interact: blog_name = &blog.fqn, slug = &article.slug).to_string())), "</a>"
 | |
|                 ))
 | |
|             </p>
 | |
|             <section class="actions">
 | |
|                 <div class="likes">
 | |
|                     <p aria-label="@i18n!(ctx.1, "One like", "{0} likes"; n_likes)" title="@i18n!(ctx.1, "One like", "{0} likes"; n_likes)">
 | |
|                         @n_likes
 | |
|                     </p>
 | |
|                     <a href="@uri!(posts::remote_interact: blog_name = &blog.fqn, slug = &article.slug)" class="action">@icon!("heart") @i18n!(ctx.1, "Add yours")</a>
 | |
|                 </div>
 | |
| 
 | |
|                 <div class="reshares">
 | |
|                     <p aria-label="@i18n!(ctx.1, "One boost", "{0} boost"; n_reshares)" title="@i18n!(ctx.1, "One boost", "{0} boosts"; n_reshares)">
 | |
|                         @n_reshares
 | |
|                     </p>
 | |
|                     <a href="@uri!(posts::remote_interact: blog_name = &blog.fqn, slug = &article.slug)" class="action">@icon!("repeat") @i18n!(ctx.1, "Boost")</a>
 | |
|                 </div>
 | |
|             </section>
 | |
|         }
 | |
|         <section class="banner">
 | |
|             <div class="flex p-author h-card user" dir="auto">
 | |
|                 @avatar(ctx.0, &author, Size::Medium, true, ctx.1)
 | |
|                 <div class="grow">
 | |
|                     <h2 class="p-name">
 | |
|                         <a href="@uri!(user::details: name = &author.fqn)">@author.name()</a>
 | |
|                         <a rel="author" class="u-url" href="@author.ap_url"></a>
 | |
|                     </h2>
 | |
|                     <p>@Html(&author.summary_html)</p>
 | |
|                 </div>
 | |
|         	    @if !ctx.2.as_ref().map(|u| u.id == author.id).unwrap_or(false) {
 | |
|                     <form action="@uri!(user::follow: name = &author.fqn)" method="POST">
 | |
|                         <input type="submit" class="button" value="@if is_following {@i18n!(ctx.1, "Unsubscribe")} else {@i18n!(ctx.1, "Subscribe")}">
 | |
|                     </form>
 | |
|         	    }
 | |
|             </div>
 | |
|         </section>
 | |
|         <section class="comments" dir="auto">
 | |
|             <h2>@i18n!(ctx.1, "Comments")</h2>
 | |
| 
 | |
|             @if ctx.2.is_some() {
 | |
|                 <form method="post" action="@uri!(comments::create: blog_name = &blog.fqn, slug = &article.slug)">
 | |
|                     @(Input::new("warning", i18n!(ctx.1, "Content warning"))
 | |
|                         .default(&comment_form.warning)
 | |
|                         .error(&comment_errors)
 | |
|                         .optional()
 | |
|                         .html(ctx.1))
 | |
| 
 | |
|                     <label for="plume-editor">@i18n!(ctx.1, "Your comment")</label>
 | |
|                     @if let Some(ref prev) = previous_comment {
 | |
|                         <input type="hidden" name="responding_to" value="@prev.id"/>
 | |
|                     }
 | |
|                     <textarea id="plume-editor" name="content" dir="auto">@comment_form.content</textarea>
 | |
|                     <input type="submit" value="@i18n!(ctx.1, "Submit comment")" />
 | |
|                 </form>
 | |
|             }
 | |
| 
 | |
|             @if !comments.is_empty() {
 | |
|                 @for comm in comments {
 | |
|                     @:comment(ctx, &comm, Some(&article.ap_url), &blog.fqn, &article.slug)
 | |
|                 }
 | |
|             } else {
 | |
|                 <p class="center" dir="auto">@i18n!(ctx.1, "No comments yet. Be the first to react!")</p>
 | |
|             }
 | |
|         </section>
 | |
|     </div>
 | |
| </div>
 | |
| @if  ctx.2.clone().and_then(|u| article.is_author(ctx.0, u.id).ok()).unwrap_or(false) {
 | |
|     <aside class="bottom-bar">
 | |
|         <div>
 | |
|             <form class="inline" method="post" action="@uri!(posts::delete: blog_name = &blog.fqn, slug = &article.slug)">
 | |
|                 <input class="button destructive" onclick="return confirm('@i18n!(ctx.1, "Are you sure?")')" type="submit" value="@i18n!(ctx.1, "Delete")">
 | |
|             </form>
 | |
|         </div>
 | |
|         <div>
 | |
|             @if !article.published {
 | |
|                 <p>@i18n!(ctx.1, "This article is still a draft. Only you and other authors can see it.")</p>
 | |
|             } else {
 | |
|                 <p>@i18n!(ctx.1, "Only you and other authors can edit this article.")</p>
 | |
|             }
 | |
|         </div>
 | |
|         <div>
 | |
|             @if !article.published {
 | |
|                 <a class="button secondary" href="@uri!(posts::edit: blog = &blog.fqn, slug = &article.slug)">@i18n!(ctx.1, "Publish")</a>
 | |
|             }
 | |
|             <a class="button" href="@uri!(posts::edit: blog = &blog.fqn, slug = &article.slug)">@i18n!(ctx.1, "Edit")</a>
 | |
|         </div>
 | |
|     </aside>
 | |
| }
 | |
| })
 |