Blog components and sample pages

v0.0.1

The blog ships as seventeen components, installed for each site when you set the blog up: eleven blocks that read and draw records, and six pieces the blocks share. This page lists the attributes of each one, the shared attributes, the stylesheet, and the nine sample pages that arrange them. To place a block on a page, follow Show the blog on your own pages.

How the blocks behave

  • Each block can run its own query, so you can place any of them on any page, alone or beside the others.
  • Every read is the public read of the record, made as the visitor the page passes in current_user. A record locked to permissions the visitor does not hold is left out, and a guest sees no locked record.
  • Eight blocks declare page_source. Such a block takes the rows the page already read for the address, when they are exactly the read it would make for this visitor. Otherwise it reads for itself, as it does without them. See Page source: read a page's rows once.
  • A block reads its first page together with the page. Later pages, filters and sorting load in the background behind a skeleton. A failed read shows a line and a button to try again.
  • The blocks are plain HTML and Tailwind classes. They need no other UI kit.
  • blog-post-detail and blog-related-posts read in step with the page every time. blog-post-search reads in step with the reader's typing, and its bar variant counts the posts in step with the page.

Attributes many blocks share

AttributeDefaultBlocksMeaning
languageEmptyEvery blockWhich edition of each record to show. Empty shows one edition of each record, the original. A code such as fa shows that language only. all shows every translation. On blog-post-detail, blog-post-comments and blog-related-posts, a code serves only a post written in that language, and empty or all lets the slug alone decide. A blogger and a team are one record in every language, so on blog-people and the two profiles the value sets the language of the links. On a profile it also picks which of the posts are listed. Empty on blog-people uses the site's first language.
post_baseEmptyblog-post-list, blog-featured-posts, blog-post-search, blog-post-detail, blog-category-list, blog-related-posts, blog-author-profile, blog-team-profileWhere posts live, such as /:lang/blog. Left empty, the block writes no link to a post. blog-post-list and blog-featured-posts open the post beside the list instead, through post_param.
category_baseEmptyblog-post-detail, blog-category-listWhere categories live, such as /:lang/blog/category. Left empty, the block draws plain words.
tag_baseEmptyblog-post-detail, blog-tag-cloudWhere tags live, such as /:lang/blog/tag. Left empty, the block draws plain words.
author_baseEmptyblog-post-detail, blog-team-profile, blog-peopleWhere bloggers live, such as /:lang/blog/author. Left empty, a name carries no link.
team_baseEmptyblog-author-profile, blog-peopleWhere teams live, such as /:lang/blog/team. Left empty, the block draws plain words.
lang_paramEmptyEvery block but blog-post-comments and blog-related-postsThe query key that carries the language on the links the block writes, such as lang. Leave it empty when the language is part of the path.
paramsEmpty mapEvery block but blog-peopleThe page's query string and captures, such as @query_params. The links and the pager a block writes keep every key the page had. A few blocks read one key only: see selected_param and post_param.
page_parampageblog-post-list, blog-author-profile, blog-team-profileThe query key for the page number. Two lists on one page need two keys. A page past the last one answers the site's 404.
current_userNoneEvery blockThe signed-in reader. Pass assigns[:current_user].
page_sourceNoneblog-post-list, blog-featured-posts, blog-post-search, blog-post-detail, blog-post-comments, blog-related-posts, blog-author-profile, blog-team-profileThe rows the page read for this address. Pass assigns[:page_source]. The block takes a row only when the page read it for this site, this reader and exactly the read the block would make. See A block must declare page_source.
loading_text, empty_text, retry_textEnglish wordsEvery block but blog-post-detail, blog-post-search and blog-related-postsWhat a block says while it loads, when it has nothing to show, and on the button that asks again.
error_textEnglish wordsThe same eight blocksWhat a block says when a read fails. On blog-post-comments it is what a reader sees when the site refuses their comment, and failed_text covers a failed read.
featured_textFeaturedblog-post-list, blog-featured-posts, blog-post-detail, blog-author-profile, blog-team-profileThe badge of a featured post.
locked_textMembers, and Members only on blog-post-detailblog-post-list, blog-featured-posts, blog-post-detailThe badge of a post that is open to some readers only.
minutes_textminblog-post-list, blog-featured-postsWhat a post's reading time is counted in.
first_text, previous_text, next_text, last_textFirst, Previous, Next, Lastblog-post-list, blog-author-profile, blog-team-profileThe pager's labels.
restNoneEvery block and every pieceExtra HTML attributes for the outer element.

Write :lang in a base and each link is built in the language of the record it points at, at the address the site's URL mode gives that language. A base with no :lang is used as written.

blog-post-list

Published posts, paged, as a grid of cards or a compact list. A row of the site's categories can sit beside the heading.

AttributeDefaultMeaning
headingLatest postsThe words above the list. Left empty, none are drawn.
search_heading, tag_headingEmptyThe words above the list while a search or a tag narrows it, in place of heading. Left empty, heading stays.
variantgridgrid or compact. Compact draws titles and dates, for a sidebar.
per_page5Posts on one page, 1 to 50.
sortnewestnewest or oldest.
collectionEmptyA category's slug. Lists that category's posts only.
tagEmptyA tag's slug. Lists posts with that tag only.
searchEmptyThe words a reader searched for. Lists the posts whose title or summary contains them, whatever the case.
featured_onlyOffLists only featured posts, paged. blog-featured-posts is the strip, which pages nothing.
exclude_slugEmptyA post to leave out, usually the one open on the page.
exclude_featured0Leaves out the newest featured posts, this many, 0 to 50. Set it to the strip's limit so no post shows twice.
show_filter_titleOnWhen a category or tag narrows the list, head it with that name and description.
show_excerpt, show_date, show_pagerOnDraw each summary, each date, and the pager.
show_sort, show_totalOffLet the reader flip the order, and draw how many posts there are.
baseEmptyThe address the pager writes its links to. Left empty, the pager draws buttons and stays on the server.
post_parampostThe query key for a post's slug, when a post opens beside the list.
chips_baseEmptyWhere a category's posts live, such as /:lang/blog/category. Set it and a row of the site's categories sits beside the heading, each a link to its posts, with the one named by collection marked. Left empty, no row is drawn.
chips_limit12How many categories the row holds at most, 1 to 40.
all_hrefEmptyWhere the first chip, every post, goes. Left empty, it goes to base.
clear_hrefEmptyWhere the way out of a filter goes: the chip of a tag, and the link a list that matched nothing offers. Left empty, neither is a link.
chips_label, all_text, tagged_text, clear_textCategories, All, Empty, Clear filtersWhat a screen reader is told the row of categories is, the first chip, the words in front of the chip a tag filter draws (left empty, no chip), and the way out of a list that matched nothing.
showing_text, of_textShowing, ofThe first word of the line under the pager, and the word between the posts on the page and all of them.
post_text, total_textpost, postsWhat the total is counted in for one post and for any other number.
newest_text, oldest_textNewest first, Oldest firstThe sort button's words while the newest or the oldest posts are on top.
no_match_textNo posts match.Said when the words a reader searched for match nothing.

blog-post-search

A search box over published posts. As a box it matches the title, narrows as the reader types, and reads nothing until they type. As a bar it is a form that sends the words to the page and says how many posts there are to search.

AttributeDefaultMeaning
variantboxbox lists the matching titles under the field, for a sidebar. bar draws a large field with the number of posts in it and sends the words to action as q, for the top of a page.
actionEmptyWhere the bar sends the words: the address of the page it is on. The bar fills its field from q in params and carries every other key through a search.
headingEmptyThe words above the box. The bar draws none.
placeholderSearch posts…What the empty field says.
per_page8Results the box shows at once, 1 to 50.
collection, tagEmptyA category's or a tag's slug. The bar counts that category's or tag's posts only. Left empty, it counts every post the reader may open.
post_text, posts_textpost, postsWhat the bar counts its posts in, for one post and for any other number.
none_textNothing matchesSaid when the box finds nothing. The reader's words follow it.

blog-tag-cloud

The site's tags, read in the background, as a row of chips or as a cloud where a tag is larger the more posts it has.

AttributeDefaultMeaning
headingEmptyThe words above the tags. Left empty, none are drawn.
variantchipschips draws a row of small tags, for a sidebar. cloud draws a panel in which a tag is as large as it is used.
mastheadOffDraw heading as the title of a page, with eyebrow above it and the number of tags under it.
eyebrowEmptyThe small words above the title. Drawn only with masthead.
summary_texttopics · larger means more posts.What follows the number of tags under the title, such as 24 topics. Drawn only with masthead.
limit20How many tags at most, 1 to 100.
sortpopularpopular, name or recent. Popular counts the same posts the number beside a tag does, whatever language they are written in.
show_countOffDraw how many published posts carry each tag, whatever language they are written in.
hide_emptyOnLeave out tags no published post carries.
selected_paramslugThe key in params that holds the tag the reader is on, to mark it. Hand params over only from a page whose key holds a tag.

blog-post-detail

One published post in full: cover, text, authors, and the rows of categories and tags. It does not list the post's translations. The layout's header offers them.

AttributeDefaultMeaning
slugNoneThe post to draw. A page that carries the slug in its address should use post_param instead.
post_parampostThe key in params that holds the slug: post for /blog?post=x, slug for a page at /:lang/blog/:slug.
baseEmptyThe path the post links back to, when it opens beside a list.
show_cover, show_excerpt, show_date, show_reading_time, show_authors, show_categories, show_tagsOnDraw the cover; the summary; the publish date and last edit; the reading time; the authors; the categories; the tags.
idle_text, missing_textEnglish wordsSaid when the address names no post, and when it names one nobody can read.
back_text, close_text, permalink_textAll posts, Close, Open this post on its own pageThe link back to the blog's front page above the post, drawn only where post_base says where the blog lives. The link back to the list, when the post opens beside one. The link to the post's own page.
cover_textcover imageThe caption of the stand-in drawn where a post has no cover image. Left empty, the stand-in carries the post's first letter alone.
reading_text, updated_text, authors_text, tags_textmin read, Updated, Empty, TagsWhat the reading time is counted in, what precedes the date of the last edit, what precedes the author names (left empty, the names stand alone), and what precedes the tags.

blog-category-list

The blog's categories, read in the background, as a menu or as cards.

AttributeDefaultMeaning
headingEmptyThe words above the categories. Left empty, none are drawn.
variantlistlist draws a narrow column. cards draws a panel for each category, with its latest posts and a link to them all.
mastheadOffDraw heading as the title of a page, with eyebrow above it.
eyebrowEmptyThe small words above the title. Drawn only with masthead.
parentEmptyEmpty lists the top-level categories. A slug lists that category's children. all lists every category, flat.
limit20How many categories at most, 1 to 100.
posts_per_category0How many of each category's latest posts to list under it, 0 to 5.
exclude_slugEmptyA post to leave out of those titles.
show_count, show_descriptionOffDraw how many posts the category's own page lists (the published posts in its language that the reader may open), and its description.
hide_emptyOnLeave out categories with no published post.
selected_paramslugThe key in params that holds the category the reader is on. Hand params over only from a page whose key holds a category.
post_text, posts_textpost, postsWhat a card counts its posts in, for one post and for any other number.
view_all_textView all inThe words in front of the category's name on the link at the foot of a card. Left empty, no link is drawn.

Categories are listed by their Display Order, then by name.

blog-post-comments

The approved conversation under a post, lengthened with a button, and a box for signed-in readers.

AttributeDefaultMeaning
slugNoneThe post, named outright. A page that carries the slug should use post_param.
post_paramslugThe key in params that holds the post's slug.
per_page10Comments shown before the reader asks for more, 1 to 50.
allow_postingOnOff keeps the comments visible and removes the box.
login_hrefNoneWhere a reader who is not signed in is sent. Empty uses the site's sign-in page in the post's language.
headingCommentsThe words above the conversation. Left empty, none are drawn.
placeholder, submit_text, reply_text, cancel_text, more_text, login_text, pending_text, pinned_text, reader_text, failed_textEnglish wordsWording. reader_text is what a commenter with no blogger profile on the site is called. pending_text is said once a comment is saved, because it is not public until a moderator approves it.

blog-author-profile

One blogger's page: picture, name, handle, bio, links, teams, how many posts a reader can open, and the published posts as cards. It makes two reads, the profile and the page of posts, so turning a page reads the posts alone.

AttributeDefaultMeaning
slugNoneThe blogger to draw. A page at /:lang/blog/author/:slug passes slug={@query_params["slug"]}.
per_page9Posts on one page, 1 to 50.
baseEmptyThe page's own address, which the pager under the posts writes its links to. Left empty, the pager draws buttons and stays on the server.
show_avatar, show_bio, show_links, show_teams, show_posts, show_excerptOnDraw the picture or the initials; the bio; the profile links; the teams; the posts; each post's summary.
teams_text, team_textTeams, TeamThe label over the teams the blogger belongs to, when it is more than one and when it is exactly one.
post_text, posts_textpost, postsThe word under the number of posts, for one post and for any other number.
posts_headingPosts by %{name}The heading over the posts, with %{name} replaced by the blogger's first name. An empty posts_heading draws none.
back_href, back_textEmptyWhere the way back above the profile leads, usually the people page, and its words. Left empty, no way back is drawn.
idle_text, missing_text, posts_loading_text, posts_error_textEnglish wordsSaid when nothing names a blogger, when the slug names nobody visible, and while or if the posts load.

blog-team-profile

One team's page: picture, name, description, how many posts a reader can open and how many members it has, then the members as cards and the posts they are credited with. It makes two reads.

AttributeDefaultMeaning
slugNoneThe team to draw. A page at /:lang/blog/team/:slug passes the capture.
per_page9Posts on one page, 1 to 50.
baseEmptyThe page's own address, which the pager under the posts writes its links to. Left empty, the pager draws buttons and stays on the server.
show_cover, show_avatar, show_description, show_members, show_bios, show_posts, show_excerptOnDraw the cover as a banner; the picture or the initials; the description; the members; a line of each member's bio; the posts; each summary.
members_heading, posts_headingMembers, Posts by %{name}Headings, with %{name} replaced by the team's name. Empty draws none.
back_href, back_textEmptyWhere the way back above the team leads, usually the people page, and its words. Left empty, no way back is drawn.
team_textTeamThe small label under the team's name. Left empty, none is drawn.
post_text, posts_text, member_text, members_textpost, posts, member, membersThe words under the number of posts and the number of members, for one and for any other number.
post_count_text, posts_count_text%{count} post, %{count} postsWhat a member's card says of their posts, with %{count} replaced by the number.
idle_text, missing_text, members_empty_text, posts_loading_text, posts_error_textEnglish wordsSaid when nothing names a team, when the slug names no active team, when a team has no visible member, and while or if the posts load.

blog-people

Every active team with its members, then the bloggers in no team, each name leading to its own page.

AttributeDefaultMeaning
headingEmptyThe words above the people. Left empty, none are drawn, which suits a page that carries its own title.
show_teams, show_unteamed, show_aboutOnDraw the teams; the bloggers in no team; a line of each bio or description.
limit50How many teams at most, and how many bloggers in no team at most, 1 to 100.
unteamed_headingWritersThe heading over the bloggers in no team. Empty draws none.
members_empty_textNobody is in this team yet.Said by a team with no visible member.
team_textTeamThe word before a team's number of members, in the corner of its card.
post_text, posts_text%{count} post, %{count} postsWhat a blogger's card says of their posts, with %{count} replaced by the number.

Pieces

The pieces hold nothing and read nothing. Restyle one and every block that draws it changes.

PieceDrawn byAttributes
blog-post-cardblog-post-list, blog-featured-posts, blog-post-detail, blog-related-posts, both profilespost, variant (grid, feature, side, related, compact or hero), show_excerpt, show_date, navigate, patch, featured_text, locked_text, minutes_text, minutes_long_text, cover_text
blog-post-metablog-post-card, in its compact variantvariant (grid or compact), published_at, show_date, show_read, navigate, patch, read_text
blog-term-rowblog-post-detaillabel, terms, role, item_role, kind (category or tag)
blog-pagerblog-post-list and both profilespage, pages, total, per_page, base, params, page_param, role, target, the four pager labels, showing_text, of_text
blog-noticeEvery block but blog-post-search and blog-related-poststone (loading, empty or error), text, role, quiet, target, retry_text, action_text, action_href
blog-profile-cardBoth profiles, blog-people, blog-post-card and blog-post-detailname, handle, image, about, variant (card, compact or avatar), navigate, role, count_text, tone (card or sunk), size (xs, sm, md, lg or custom), stacked, class, decorative

The stylesheet blog-code-highlight colours the code blocks in a post's body, in the Monokai style. It is installed per site as a base stylesheet, so a site's own custom stylesheets win over it.

Sample pages

Setting up writes these pages. Each draws its blocks with language set to the page's language, and a path that starts with /:lang.

PagePathShows eachBlocks
Blog/:lang/blogNoneblog-post-search as a bar, blog-featured-posts, blog-post-list under a row of categories
Blog post/:lang/blog/:slugPost, blog:postblog-post-detail, blog-post-comments, blog-related-posts
Blog category/:lang/blog/category/:slugCollection, blog:categoryblog-post-search as a bar, blog-post-list with collection
Blog tag/:lang/blog/tag/:slugTag, blog:tagblog-post-search as a bar, blog-post-list with tag
Blog categories/:lang/blog/categoriesNoneblog-category-list as cards, with up to 60 categories and their three latest posts each
Blog tags/:lang/blog/tagsNoneblog-tag-cloud as a cloud with up to 100 tags
Blog author/:lang/blog/author/:slugBlogger, blog:authorblog-author-profile
Blog team/:lang/blog/team/:slugTeam, blog:teamblog-team-profile
Blog people/:lang/blog/peopleNoneblog-people

Every sample page hangs on the site's site-main layout. The layout draws the header, a bar with the blog's four places (Posts, Categories, Tags and People) and the footer, and the page draws only what lies between them. See Draw an extension's pages in the site layout.

No sample page uses the saved snippet Blog sidebar. It is there for pages of your own: a search box, a category list with each category's three latest posts, a tag cloud of 24 tags and a compact list of the five most recent posts. The bare address /blog is not written, because a page there could not fill the language in its links. Setting up never overwrites a page. A page whose address you already use is left out, and one whose name you already use is written under another name.