mirror of
https://git.joinplu.me/Plume/Plume.git
synced 2024-11-29 23:11:02 +00:00
0d708e1639
Add support for remote interaction ([this thing](https://eldritch.cafe/users/Barmaid/remote_follow) in mastodon) - [x] create the endpoint dispatching remote interactions to local pages - [x] add this endpoint to web-finger - [x] propose remote interaction when following and not connected - [x] propose remote interaction when liking/sharing and not connected - [x] propose remote interaction when commenting and not connected - [x] fetch posts/comments we don't know but remote interaction was requested for ?
161 lines
7.9 KiB
HTML
161 lines
7.9 KiB
HTML
@use templates::{base, partials::comment};
|
|
@use template_utils::*;
|
|
@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 validator::ValidationErrors;
|
|
@use routes::comments::NewCommentForm;
|
|
@use 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"/>
|
|
}, {
|
|
<a href="@uri!(blogs::details: name = &blog.fqn, page = _)">@blog.title</a>
|
|
}, {
|
|
<div class="h-entry">
|
|
<h1 class="article p-name">@article.title</h1>
|
|
<h2 class="article p-summary">@article.subtitle</h2>
|
|
<div class="article-info">
|
|
<span class="author">
|
|
@Html(i18n!(ctx.1, "Written by {0}"; format!("<a href=\"{}\">{}</a>",
|
|
uri!(user::details: name = &author.fqn),
|
|
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>
|
|
@if ctx.2.clone().map(|u| u.id == author.id).unwrap_or(false) {
|
|
—
|
|
<a href="@uri!(posts::edit: blog = &blog.fqn, slug = &article.slug)">@i18n!(ctx.1, "Edit")</a>
|
|
—
|
|
<form class="inline" method="post" action="@uri!(posts::delete: blog_name = &blog.fqn, slug = &article.slug)">
|
|
<input onclick="return confirm('@i18n!(ctx.1, "Are you sure?")')" type="submit" value="@i18n!(ctx.1, "Delete this article")">
|
|
</form>
|
|
}
|
|
@if !article.published {
|
|
<span class="badge">@i18n!(ctx.1, "Draft")</span>
|
|
}
|
|
</div>
|
|
@if article.cover_id.is_some() {
|
|
<div class="cover" style="background-image: url('@Html(article.cover_url(ctx.0).unwrap_or_default())')"></div>
|
|
<img class="hidden u-photo" src="@article.cover_url(ctx.0).unwrap_or_default()"/>
|
|
}
|
|
<article class="e-content">
|
|
@Html(&article.content)
|
|
</article>
|
|
<div class="article-meta">
|
|
<p>
|
|
@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>
|
|
<ul class="tags">
|
|
@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>
|
|
<div class="flex p-author h-card">
|
|
@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)</h2>
|
|
</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>
|
|
@if ctx.2.is_some() {
|
|
<div 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>
|
|
</div>
|
|
} 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='{}'>", uri!(session::new: m = _)), "</a>",
|
|
format!("<a href='{}'>", uri!(posts::remote_interact: blog_name = &blog.fqn, slug = &article.slug)), "</a>"
|
|
))</p>
|
|
<div 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>
|
|
</div>
|
|
}
|
|
<div class="comments">
|
|
<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!(ctx.1, warning (optional text), "Content warning", comment_form, comment_errors, "")
|
|
|
|
<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">@comment_form.content</textarea>
|
|
<input type="submit" value="@i18n!(ctx.1, "Submit comment")" />
|
|
</form>
|
|
}
|
|
|
|
@if !comments.is_empty() {
|
|
<div class="list">
|
|
@for comm in comments {
|
|
@:comment(ctx, &comm, Some(&article.ap_url), &blog.fqn, &article.slug)
|
|
}
|
|
</div>
|
|
} else {
|
|
<p class="center">@i18n!(ctx.1, "No comments yet. Be the first to react!")</p>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
})
|