Use Ructe (#327)
All the template are now compiled at compile-time with the `ructe` crate.
I preferred to use it instead of askama because it allows more complex Rust expressions, where askama only supports a small subset of expressions and doesn't allow them everywhere (for instance, `{{ macro!() | filter }}` would result in a parsing error).
The diff is quite huge, but there is normally no changes in functionality.
Fixes #161 and unblocks #110 and #273
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
{% extends "base" %}
|
||||
{% import "macros" as macros %}
|
||||
|
||||
{% block title %}
|
||||
{{ "Dashboard" | _ }}
|
||||
{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ "Your Dashboard" | _ }}</h1>
|
||||
|
||||
<section>
|
||||
<h2>{{ "Your Blogs" | _ }}</h2>
|
||||
{% if blogs | length < 1 %}
|
||||
<p>{{ "You don't have any blog yet. Create your own, or ask to join one." | _ }}</p>
|
||||
{% endif %}
|
||||
<div class="cards">
|
||||
{% for blog in blogs %}
|
||||
<div class="card">
|
||||
<h3><a href="/~/{{ blog.actor_id }}/">{{ blog.title }}</a></h3>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<a class="button" href="/blogs/new">{{ "Start a new blog" | _ }}</a>
|
||||
</section>
|
||||
|
||||
{% if drafts | length > 0 %}
|
||||
<section>
|
||||
<h2>{{ "Your Drafts" | _ }}</h2>
|
||||
<div class="cards">
|
||||
{% for draft in drafts %}
|
||||
{{ macros::post_card(article=draft) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
<section>
|
||||
<h2>{{ "Your media" | _ }}</h2>
|
||||
<a class="button" href="/medias">{{ "Go to your gallery" | _ }}</a>
|
||||
</section>
|
||||
{% endblock content %}
|
||||
@@ -0,0 +1,41 @@
|
||||
@use templates::{base, partials::post_card};
|
||||
@use template_utils::*;
|
||||
@use plume_models::blogs::Blog;
|
||||
@use plume_models::posts::Post;
|
||||
|
||||
@(ctx: BaseContext, blogs: Vec<Blog>, drafts: Vec<Post>)
|
||||
|
||||
@:base(ctx, "Your Dashboard", {}, {}, {
|
||||
<h1>@i18n!(ctx.1, "Your Dashboard")</h1>
|
||||
|
||||
<section>
|
||||
<h2>@i18n!(ctx.1, "Your Blogs")</h2>
|
||||
@if blogs.is_empty() {
|
||||
<p>@i18n!(ctx.1, "You don't have any blog yet. Create your own, or ask to join one.")</p>
|
||||
}
|
||||
<div class="cards">
|
||||
@for blog in blogs {
|
||||
<div class="card">
|
||||
<h3><a href="/~/@blog.actor_id/">@blog.title</a></h3>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<a class="button" href="/blogs/new">@i18n!(ctx.1, "Start a new blog")</a>
|
||||
</section>
|
||||
|
||||
@if !drafts.is_empty() {
|
||||
<section>
|
||||
<h2>@i18n!(ctx.1, "Your Drafts")</h2>
|
||||
<div class="cards">
|
||||
@for draft in drafts {
|
||||
@:post_card(ctx, draft)
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
|
||||
<section>
|
||||
<h2>@i18n!(ctx.1, "Your media")</h2>
|
||||
<a class="button" href="/medias">@i18n!(ctx.1, "Go to your gallery")</a>
|
||||
</section>
|
||||
})
|
||||
@@ -1,41 +0,0 @@
|
||||
{% extends "base" %}
|
||||
{% import "macros" as macros %}
|
||||
|
||||
{% block title %}
|
||||
{% if user.display_name %}
|
||||
{% set name = user.display_name %}
|
||||
{% else %}
|
||||
{% set name = user.username %}
|
||||
{% endif %}
|
||||
|
||||
{{ name }}
|
||||
{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
{% include "users/header" %}
|
||||
|
||||
{% set user_link = ['/@', user.fqn] %}
|
||||
{% set followers_link = ['/@', user.fqn, 'followers'] %}
|
||||
{{ macros::tabs(links=[ user_link | join(sep='/'), followers_link | join(sep='/')], titles=['Articles', 'Followers'], selected=1) }}
|
||||
|
||||
{% if recents | length != 0 %}
|
||||
<h2>
|
||||
{{ "Latest articles" | _ }}
|
||||
<small><a href="/@/{{ user.fqn }}/atom.xml" title="Atom feed">{{ macros::feather(name="rss") }}</a></small>
|
||||
</h2>
|
||||
<div class="cards">
|
||||
{% for article in recents %}
|
||||
{{ macros::post_card(article=article) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if reshares | length != 0 %}
|
||||
<h2>{{ "Recently boosted" | _ }}</h2>
|
||||
<div class="cards">
|
||||
{% for article in reshares %}
|
||||
{{ macros::post_card(article=article) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
@@ -0,0 +1,36 @@
|
||||
@use templates::{base, partials::post_card, users::header};
|
||||
@use template_utils::*;
|
||||
@use plume_models::posts::Post;
|
||||
@use plume_models::users::User;
|
||||
|
||||
@(ctx: BaseContext, user: User, follows: bool, is_remote: bool, remote_url: String, recents: Vec<Post>, reshares: Vec<Post>)
|
||||
|
||||
@:base(ctx, &user.name(ctx.0), {}, {}, {
|
||||
@:header(ctx, &user, follows, is_remote, remote_url)
|
||||
|
||||
@tabs(&[
|
||||
(&format!("/@/{}", user.get_fqn(ctx.0)), i18n!(ctx.1, "Articles"), true),
|
||||
(&format!("/@/{}/followers", user.get_fqn(ctx.0)), i18n!(ctx.1, "Followers"), false)
|
||||
])
|
||||
|
||||
@if !recents.is_empty() {
|
||||
<h2>
|
||||
@i18n!(ctx.1, "Latest articles")
|
||||
<small><a href="/@@/@user.get_fqn(ctx.0)/atom.xml" title="@i18n!(ctx.1, "Atom feed")">@icon!("rss")</a></small>
|
||||
</h2>
|
||||
<div class="cards">
|
||||
@for article in recents {
|
||||
@:post_card(ctx, article)
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@if !reshares.is_empty() {
|
||||
<h2>@i18n!(ctx.1, "Recently boosted")</h2>
|
||||
<div class="cards">
|
||||
@for article in reshares {
|
||||
@:post_card(ctx, article)
|
||||
}
|
||||
</div>
|
||||
}
|
||||
})
|
||||
@@ -1,34 +0,0 @@
|
||||
{% extends "base" %}
|
||||
|
||||
{% block title %}
|
||||
{{ "Edit your account" | _ }}
|
||||
{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ "Your Profile" | _ }}</h1>
|
||||
<form method="post">
|
||||
<!-- Rocket hack to use various HTTP methods -->
|
||||
<input type=hidden name="_method" value="put">
|
||||
|
||||
<label for="display_name">{{ "Display Name" | _ }}</label>
|
||||
<input name="display_name" value="{{ account.display_name }}">
|
||||
|
||||
<label for="email">{{ "Email" | _ }}</label>
|
||||
<input name="email" value="{{ account.email }}">
|
||||
|
||||
<label for="summary">{{ "Summary" | _ }}</label>
|
||||
<input name="summary" value="{{ account.summary }}">
|
||||
|
||||
<input type="submit" value="{{ "Update account" | _ }}"/>
|
||||
</form>
|
||||
|
||||
<h2>{{ "Danger zone" | _ }}</h2>
|
||||
<p>{{ "Be very careful, any action taken here can't be cancelled." | _ }}
|
||||
{% if not account.is_admin %}
|
||||
<form method="post" action="/@/{{ account.fqn }}/delete">
|
||||
<input type="submit" class="inline-block button destructive" value="{{ 'Delete your account' | _ }}">
|
||||
</form>
|
||||
{% else %}
|
||||
<p>{{ "Sorry, but as an admin, you can't leave your instance." | _ }}</p>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
@@ -0,0 +1,30 @@
|
||||
@use templates::base;
|
||||
@use template_utils::*;
|
||||
@use routes::user::UpdateUserForm;
|
||||
@use validator::ValidationErrors;
|
||||
|
||||
@(ctx: BaseContext, form: UpdateUserForm, errors: ValidationErrors)
|
||||
|
||||
@:base(ctx, "Edit your account", {}, {}, {
|
||||
<h1>@i18n!(ctx.1, "Your Profile")</h1>
|
||||
<form method="post">
|
||||
<!-- Rocket hack to use various HTTP methods -->
|
||||
<input type=hidden name="_method" value="put">
|
||||
|
||||
@input!(ctx.1, display_name (text), "Display name", form, errors.clone())
|
||||
@input!(ctx.1, email (text), "Email", form, errors.clone())
|
||||
@input!(ctx.1, summary (text), "Summary", form, errors)
|
||||
|
||||
<input type="submit" value="@i18n!(ctx.1, "Update account")"/>
|
||||
</form>
|
||||
|
||||
<h2>@i18n!(ctx.1, "Danger zone")</h2>
|
||||
<p>@i18n!(ctx.1, "Be very careful, any action taken here can't be cancelled.")
|
||||
@if !ctx.2.clone().expect("Editing profile while not connected").is_admin {
|
||||
<form method="post" action="/@@/@ctx.2.clone().expect("Editing profile while not connected").get_fqn(ctx.0)/delete">
|
||||
<input type="submit" class="inline-block button destructive" value="@i18n!(ctx.1, "Delete your account")">
|
||||
</form>
|
||||
} else {
|
||||
<p>@i18n!(ctx.1, "Sorry, but as an admin, you can't leave your instance.")</p>
|
||||
}
|
||||
})
|
||||
@@ -1,24 +0,0 @@
|
||||
{% extends "base" %}
|
||||
{% import "macros" as macros %}
|
||||
|
||||
{% block title %}
|
||||
{{ "{{ name | escape }}'s followers" | _(name=user.name) }}
|
||||
{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
{% include "users/header" %}
|
||||
|
||||
{% set user_link = ['/@', user.fqn] %}
|
||||
{% set followers_link = ['/@', user.fqn, 'followers'] %}
|
||||
{{ macros::tabs(links=[ user_link | join(sep='/'), followers_link | join(sep='/')], titles=['Articles', 'Followers'], selected=2) }}
|
||||
|
||||
<div class="cards">
|
||||
{% for follower in followers %}
|
||||
<div class="card">
|
||||
<h3><a href="/@/{{ follower.fqn }}/">{{ follower.name }}</a> <small>@{{ follower.fqn }}</small></h3>
|
||||
<main><p>{{ follower.summary | safe }}</p></main>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{{ macros::paginate(page=page, total=n_pages) }}
|
||||
{% endblock content %}
|
||||
@@ -0,0 +1,24 @@
|
||||
@use templates::{base, users::header};
|
||||
@use template_utils::*;
|
||||
@use plume_models::users::User;
|
||||
|
||||
@(ctx: BaseContext, user: User, follows: bool, is_remote: bool, remote_url: String, followers: Vec<User>, page: i32, n_pages: i32)
|
||||
|
||||
@:base(ctx, &i18n!(ctx.1, "{0}'s followers"; user.name(ctx.0)), {}, {}, {
|
||||
@:header(ctx, &user, follows, is_remote, remote_url)
|
||||
|
||||
@tabs(&[
|
||||
(&format!("/@/{}", user.get_fqn(ctx.0)), i18n!(ctx.1, "Articles"), false),
|
||||
(&format!("/@/{}/followers", user.get_fqn(ctx.0)), i18n!(ctx.1, "Followers"), true)
|
||||
])
|
||||
|
||||
<div class="cards">
|
||||
@for follower in followers {
|
||||
<div class="card">
|
||||
<h3><a href="/@@/@follower.get_fqn(ctx.0)/">@follower.name(ctx.0)</a> <small>@format!("@{}", follower.get_fqn(ctx.0))</small></h3>
|
||||
<main><p>@Html(follower.summary)</p></main>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@paginate(ctx.1, page, n_pages)
|
||||
})
|
||||
@@ -1,44 +0,0 @@
|
||||
<div class="user">
|
||||
<div class="flex wrap">
|
||||
{{ macros::avatar(user=user, size="medium") }}
|
||||
|
||||
<h1 class="grow flex vertical">
|
||||
{{ user.name }}
|
||||
<small>@{{ user.fqn }}</small>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
{% if user.is_admin %}
|
||||
<span class="badge">{{ "Admin" | _ }}</span>
|
||||
{% endif %}
|
||||
|
||||
{% if is_self %}
|
||||
<span class="badge">{{ "It is you" | _ }}</span>
|
||||
{% endif %}
|
||||
|
||||
{% if is_self %}
|
||||
<a href="/@/{{ user.username }}/edit" class="button inline-block">{{ "Edit your profile" | _ }}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% if is_remote %}
|
||||
<a class="inline-block" href="{{ user.ap_url }}" target="_blank">{{ "Open on {{ instance_url }}" | _(instance_url=instance_url) }}</a>
|
||||
{% endif %}
|
||||
|
||||
{% set not_self = not is_self %}
|
||||
{% if not_self and (account is defined) %}
|
||||
<form class="inline" method="post" action="/@/{{ user.fqn }}/follow/">
|
||||
{% if follows %}
|
||||
<input type="submit" value="{{ 'Unfollow' | _ }}">
|
||||
{% else %}
|
||||
<input type="submit" value="{{ 'Follow' | _ }}">
|
||||
{% endif %}
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="user-summary">
|
||||
{{ user.summary | safe }}
|
||||
</div>
|
||||
@@ -0,0 +1,43 @@
|
||||
@use template_utils::*;
|
||||
@use plume_models::users::User;
|
||||
|
||||
@(ctx: BaseContext, user: &User, follows: bool, is_remote: bool, instance_url: String)
|
||||
|
||||
<div class="user">
|
||||
<div class="flex wrap">
|
||||
@avatar(ctx.0, &user, Size::Medium, false, ctx.1)
|
||||
|
||||
<h1 class="grow flex vertical">
|
||||
@user.name(ctx.0)
|
||||
<small>@user.get_fqn(ctx.0)</small>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
@if user.is_admin {
|
||||
<span class="badge">@i18n!(ctx.1, "Admin")</span>
|
||||
}
|
||||
|
||||
@if ctx.2.clone().map(|u| u.id == user.id).unwrap_or(false) {
|
||||
<span class="badge">@i18n!(ctx.1, "It is you")</span>
|
||||
<a href="/@@/@user.username/edit" class="button inline-block">@i18n!(ctx.1, "Edit your profile")</a>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@if is_remote {
|
||||
<a class="inline-block" href="@user.ap_url" target="_blank">@i18n!(ctx.1, "Open on {0}"; instance_url)</a>
|
||||
}
|
||||
|
||||
@if ctx.2.clone().map(|u| u.id != user.id).unwrap_or(false) {
|
||||
<form class="inline" method="post" action="/@@/@user.get_fqn(ctx.0)/follow/">
|
||||
@if follows {
|
||||
<input type="submit" value="@i18n!(ctx.1, "Unfollow")">
|
||||
} else {
|
||||
<input type="submit" value="@i18n!(ctx.1, "Follow")">
|
||||
}
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
<div class="user-summary">
|
||||
@Html(user.summary.clone())
|
||||
</div>
|
||||
@@ -1,22 +0,0 @@
|
||||
{% extends "base" %}
|
||||
{% import "macros" as macros %}
|
||||
|
||||
{% block title %}
|
||||
{{ "New Account" | _ }}
|
||||
{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
{% if enabled %}
|
||||
<h1>{{ "Create an account" | _ }}</h1>
|
||||
<form method="post">
|
||||
{{ macros::input(name="username", label="Username", errors=errors, form=form, props='minlenght="1"') }}
|
||||
{{ macros::input(name="email", label="Email", errors=errors, form=form, type="email") }}
|
||||
{{ macros::input(name="password", label="Password", errors=errors, form=form, type="password", props='minlenght="8"') }}
|
||||
{{ macros::input(name="password_confirmation", label="Password confirmation", errors=errors, form=form, type="password", props='minlenght="8"') }}
|
||||
|
||||
<input type="submit" value="{{ "Create account" | _ }}" />
|
||||
</form>
|
||||
{% else %}
|
||||
<p class="center">{{ "Sorry, but registrations are closed on this instance. Try to find another one" | _ }}</p>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
@@ -0,0 +1,22 @@
|
||||
@use templates::base;
|
||||
@use template_utils::*;
|
||||
@use routes::user::NewUserForm;
|
||||
@use validator::ValidationErrors;
|
||||
|
||||
@(ctx: BaseContext, enabled: bool, form: &NewUserForm, errors: ValidationErrors)
|
||||
|
||||
@:base(ctx, "Edit your account", {}, {}, {
|
||||
@if enabled {
|
||||
<h1>@i18n!(ctx.1, "Create an account")</h1>
|
||||
<form method="post">
|
||||
@input!(ctx.1, username (text), "Username", form, errors.clone(), "minlenght=\"1\"")
|
||||
@input!(ctx.1, email (text), "Email", form, errors.clone())
|
||||
@input!(ctx.1, password (password), "Password", form, errors.clone(), "minlenght=\"8\"")
|
||||
@input!(ctx.1, password_confirmation (password), "Password confirmation", form, errors, "minlenght=\"8\"")
|
||||
|
||||
<input type="submit" value="@i18n!(ctx.1, "Create account")" />
|
||||
</form>
|
||||
} else {
|
||||
<p class="center">@i18n!(ctx.1, "Sorry, but registrations are closed on this instance. Try to find another one")</p>
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user