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-detailandblog-related-postsread in step with the page every time.blog-post-searchreads in step with the reader's typing, and itsbarvariant counts the posts in step with the page.
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.
| Attribute | Default | Meaning |
|---|---|---|
heading | Latest posts | The words above the list. Left empty, none are drawn. |
search_heading, tag_heading | Empty | The words above the list while a search or a tag narrows it, in place of heading. Left empty, heading stays. |
variant | grid | grid or compact. Compact draws titles and dates, for a sidebar. |
per_page | 5 | Posts on one page, 1 to 50. |
sort | newest | newest or oldest. |
collection | Empty | A category's slug. Lists that category's posts only. |
tag | Empty | A tag's slug. Lists posts with that tag only. |
search | Empty | The words a reader searched for. Lists the posts whose title or summary contains them, whatever the case. |
featured_only | Off | Lists only featured posts, paged. blog-featured-posts is the strip, which pages nothing. |
exclude_slug | Empty | A post to leave out, usually the one open on the page. |
exclude_featured | 0 | Leaves out the newest featured posts, this many, 0 to 50. Set it to the strip's limit so no post shows twice. |
show_filter_title | On | When a category or tag narrows the list, head it with that name and description. |
show_excerpt, show_date, show_pager | On | Draw each summary, each date, and the pager. |
show_sort, show_total | Off | Let the reader flip the order, and draw how many posts there are. |
base | Empty | The address the pager writes its links to. Left empty, the pager draws buttons and stays on the server. |
post_param | post | The query key for a post's slug, when a post opens beside the list. |
chips_base | Empty | Where 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_limit | 12 | How many categories the row holds at most, 1 to 40. |
all_href | Empty | Where the first chip, every post, goes. Left empty, it goes to base. |
clear_href | Empty | Where 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_text | Categories, All, Empty, Clear filters | What 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_text | Showing, of | The first word of the line under the pager, and the word between the posts on the page and all of them. |
post_text, total_text | post, posts | What the total is counted in for one post and for any other number. |
newest_text, oldest_text | Newest first, Oldest first | The sort button's words while the newest or the oldest posts are on top. |
no_match_text | No posts match. | Said when the words a reader searched for match nothing. |
blog-featured-posts
The posts flagged Featured, as a strip with its own read: the newest as a large card, the next ones as smaller cards beside it.
| Attribute | Default | Meaning |
|---|---|---|
heading | Featured | The words above the strip. Left empty, none are drawn. |
variant | grid | grid or compact. Compact draws titles and dates, for a sidebar. |
limit | 3 | How many posts, 1 to 50. |
sort | newest | newest or oldest. |
collection, tag, exclude_slug | Empty | As on blog-post-list. |
show_excerpt, show_date | On | Draw the summary of the large card, which the cards beside it never draw, and each date. |
spaced | Off | Leave a wide gap under the strip while it holds posts, for a strip at the top of a page. |
base, post_param | Empty, post | The page's own address and the query key, for a post that opens beside the strip. |
minutes_long_text | min read | What the reading time says on the large card. |
empty_text | Nothing is featured yet. | Said when no post is flagged. Left empty, the strip draws nothing, which suits a page where it is an extra. |
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.
| Attribute | Default | Meaning |
|---|---|---|
variant | box | box 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. |
action | Empty | Where 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. |
heading | Empty | The words above the box. The bar draws none. |
placeholder | Search posts… | What the empty field says. |
per_page | 8 | Results the box shows at once, 1 to 50. |
collection, tag | Empty | A 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_text | post, posts | What the bar counts its posts in, for one post and for any other number. |
none_text | Nothing matches | Said 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.
| Attribute | Default | Meaning |
|---|---|---|
heading | Empty | The words above the tags. Left empty, none are drawn. |
variant | chips | chips draws a row of small tags, for a sidebar. cloud draws a panel in which a tag is as large as it is used. |
masthead | Off | Draw heading as the title of a page, with eyebrow above it and the number of tags under it. |
eyebrow | Empty | The small words above the title. Drawn only with masthead. |
summary_text | topics · larger means more posts. | What follows the number of tags under the title, such as 24 topics. Drawn only with masthead. |
limit | 20 | How many tags at most, 1 to 100. |
sort | popular | popular, name or recent. Popular counts the same posts the number beside a tag does, whatever language they are written in. |
show_count | Off | Draw how many published posts carry each tag, whatever language they are written in. |
hide_empty | On | Leave out tags no published post carries. |
selected_param | slug | The 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.
| Attribute | Default | Meaning |
|---|---|---|
slug | None | The post to draw. A page that carries the slug in its address should use post_param instead. |
post_param | post | The key in params that holds the slug: post for /blog?post=x, slug for a page at /:lang/blog/:slug. |
base | Empty | The 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_tags | On | Draw the cover; the summary; the publish date and last edit; the reading time; the authors; the categories; the tags. |
idle_text, missing_text | English words | Said when the address names no post, and when it names one nobody can read. |
back_text, close_text, permalink_text | All posts, Close, Open this post on its own page | The 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_text | cover image | The 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_text | min read, Updated, Empty, Tags | What 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.
| Attribute | Default | Meaning |
|---|---|---|
heading | Empty | The words above the categories. Left empty, none are drawn. |
variant | list | list draws a narrow column. cards draws a panel for each category, with its latest posts and a link to them all. |
masthead | Off | Draw heading as the title of a page, with eyebrow above it. |
eyebrow | Empty | The small words above the title. Drawn only with masthead. |
parent | Empty | Empty lists the top-level categories. A slug lists that category's children. all lists every category, flat. |
limit | 20 | How many categories at most, 1 to 100. |
posts_per_category | 0 | How many of each category's latest posts to list under it, 0 to 5. |
exclude_slug | Empty | A post to leave out of those titles. |
show_count, show_description | Off | Draw how many posts the category's own page lists (the published posts in its language that the reader may open), and its description. |
hide_empty | On | Leave out categories with no published post. |
selected_param | slug | The 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_text | post, posts | What a card counts its posts in, for one post and for any other number. |
view_all_text | View all in | The 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.
| Attribute | Default | Meaning |
|---|---|---|
slug | None | The post, named outright. A page that carries the slug should use post_param. |
post_param | slug | The key in params that holds the post's slug. |
per_page | 10 | Comments shown before the reader asks for more, 1 to 50. |
allow_posting | On | Off keeps the comments visible and removes the box. |
login_href | None | Where a reader who is not signed in is sent. Empty uses the site's sign-in page in the post's language. |
heading | Comments | The 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_text | English words | Wording. 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-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.
| Attribute | Default | Meaning |
|---|---|---|
slug | None | The team to draw. A page at /:lang/blog/team/:slug passes the capture. |
per_page | 9 | Posts on one page, 1 to 50. |
base | Empty | The 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_excerpt | On | Draw 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_heading | Members, Posts by %{name} | Headings, with %{name} replaced by the team's name. Empty draws none. |
back_href, back_text | Empty | Where the way back above the team leads, usually the people page, and its words. Left empty, no way back is drawn. |
team_text | Team | The small label under the team's name. Left empty, none is drawn. |
post_text, posts_text, member_text, members_text | post, posts, member, members | The 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} posts | What 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_text | English words | Said 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.
| Attribute | Default | Meaning |
|---|---|---|
heading | Empty | The words above the people. Left empty, none are drawn, which suits a page that carries its own title. |
show_teams, show_unteamed, show_about | On | Draw the teams; the bloggers in no team; a line of each bio or description. |
limit | 50 | How many teams at most, and how many bloggers in no team at most, 1 to 100. |
unteamed_heading | Writers | The heading over the bloggers in no team. Empty draws none. |
members_empty_text | Nobody is in this team yet. | Said by a team with no visible member. |
team_text | Team | The word before a team's number of members, in the corner of its card. |
post_text, posts_text | %{count} post, %{count} posts | What 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.
| Piece | Drawn by | Attributes |
|---|---|---|
blog-post-card | blog-post-list, blog-featured-posts, blog-post-detail, blog-related-posts, both profiles | post, 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-meta | blog-post-card, in its compact variant | variant (grid or compact), published_at, show_date, show_read, navigate, patch, read_text |
blog-term-row | blog-post-detail | label, terms, role, item_role, kind (category or tag) |
blog-pager | blog-post-list and both profiles | page, pages, total, per_page, base, params, page_param, role, target, the four pager labels, showing_text, of_text |
blog-notice | Every block but blog-post-search and blog-related-posts | tone (loading, empty or error), text, role, quiet, target, retry_text, action_text, action_href |
blog-profile-card | Both profiles, blog-people, blog-post-card and blog-post-detail | name, 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.
| Page | Path | Shows each | Blocks |
|---|---|---|---|
| Blog | /:lang/blog | None | blog-post-search as a bar, blog-featured-posts, blog-post-list under a row of categories |
| Blog post | /:lang/blog/:slug | Post, blog:post | blog-post-detail, blog-post-comments, blog-related-posts |
| Blog category | /:lang/blog/category/:slug | Collection, blog:category | blog-post-search as a bar, blog-post-list with collection |
| Blog tag | /:lang/blog/tag/:slug | Tag, blog:tag | blog-post-search as a bar, blog-post-list with tag |
| Blog categories | /:lang/blog/categories | None | blog-category-list as cards, with up to 60 categories and their three latest posts each |
| Blog tags | /:lang/blog/tags | None | blog-tag-cloud as a cloud with up to 100 tags |
| Blog author | /:lang/blog/author/:slug | Blogger, blog:author | blog-author-profile |
| Blog team | /:lang/blog/team/:slug | Team, blog:team | blog-team-profile |
| Blog people | /:lang/blog/people | None | blog-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.