Rework post page (lead, pager), add skip link, unified focus ring, reduced motion and keyboard-accessible menu
This commit is contained in:
1 parent
ae362639e3
commit
ba65b18d29
14 files changed
+544
-69
No files matched your search
@@ -0,0 +1,65 @@
|
||||
using Elternbeirat.Contracts;
|
||||
|
||||
namespace Elternbeirat.Web.Features.Posts;
|
||||
|
||||
/// <summary>
|
||||
/// The posts next to a given post in time: the one published before it and the
|
||||
/// one published after it.
|
||||
/// </summary>
|
||||
/// <param name="Previous">
|
||||
/// The older post, or <see langword="null"/> if the post is the oldest.
|
||||
/// </param>
|
||||
/// <param name="Next">
|
||||
/// The newer post, or <see langword="null"/> if the post is the newest.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// "Previous" and "next" follow time, as a reader moving through the news would:
|
||||
/// "Vorheriger Beitrag" is the older one, "Nächster Beitrag" the newer one. The
|
||||
/// list order of the posts page (newest first) is the other way round, which is
|
||||
/// why the direction is pinned down here instead of being left to the markup.
|
||||
/// </remarks>
|
||||
/// <seealso cref="PostDetail"/>
|
||||
public sealed record PostNeighbors(Post? Previous, Post? Next)
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds the neighbours of the post with the given slug.
|
||||
/// </summary>
|
||||
/// <param name="posts">
|
||||
/// All public posts, newest first, as <c>PocketBaseClient.GetPostsAsync</c>
|
||||
/// returns them.
|
||||
/// </param>
|
||||
/// <param name="slug">The slug of the post being shown.</param>
|
||||
/// <returns>
|
||||
/// The older and the newer post. Both are <see langword="null"/> if the slug is
|
||||
/// not in the list, or if it is the only post.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// The slug is compared case-insensitively, like the route lookup in
|
||||
/// <see cref="PostDetail"/>, so a page reached as <c>/posts/New-Board</c> still
|
||||
/// gets its neighbours.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // posts = [March, February, January] (newest first)
|
||||
/// var neighbors = PostNeighbors.Of(posts, "february");
|
||||
/// // neighbors.Previous is January, neighbors.Next is March
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static PostNeighbors Of(IReadOnlyList<Post> posts, string slug) =>
|
||||
IndexOf(posts, slug) is var index and >= 0
|
||||
? new PostNeighbors(
|
||||
Previous: index + 1 < posts.Count ? posts[index + 1] : null,
|
||||
Next: index > 0 ? posts[index - 1] : null)
|
||||
: new PostNeighbors(null, null);
|
||||
|
||||
/// <summary>
|
||||
/// The position of the post with <paramref name="slug"/>, or <c>-1</c>.
|
||||
/// </summary>
|
||||
private static int IndexOf(IReadOnlyList<Post> posts, string slug) =>
|
||||
posts
|
||||
.Select((post, index) => (post, index))
|
||||
.FirstOrDefault(
|
||||
entry => string.Equals(entry.post.Slug, slug, StringComparison.OrdinalIgnoreCase),
|
||||
(null!, -1))
|
||||
.index;
|
||||
}
|
||||
Reference in new issue
Block a user