Blog
The blog home page with featured slides, categories and latest articles, rendering empty lists rather than an error when the blog fails to load.
import { Blog, BlogPage, blogLoader, BlogPageProps } from '@salla.sa/twilight-theme-engine/routes/blog';In plain words
Salla stores can publish a blog. Its home page at /blog shows featured articles in a slider, the categories beside them and a list of articles. Blog.loader fetches all of it in one request.
The component only draws the data it is given, so a route can change what appears (drop the slider, show fewer articles) through the loader's extend argument, as the demo does. The real page runs on Built-in pages.
Signature
const Blog: {
readonly id: 'blog.index';
readonly loader: (
ctx?: { locale?: string },
extend?: (data: BlogPageProps, ctx: { params: {} }) => Record<string, unknown> | Promise<Record<string, unknown>>
) => Promise<BlogPageProps>;
readonly head: (ctx: TwilightContext, data: BlogPageProps) => HeadDescriptor;
readonly Component: React.LazyExoticComponent<(props: BlogPageProps) => JSX.Element>;
};
const BlogPage: typeof Blog.Component;
function blogLoader(): Promise<BlogPageProps>;
interface BlogPageProps {
page: Page; // title: the blocks.footer.blog translation, or 'Blog'
articles: ArticleSummary[];
categories?: BlogCategoryType[];
slides?: ArticleSummary[];
popular?: ArticleSummary[]; // loaded, not drawn by BlogPage
}Try it live
Loading the blog…
// app/routes.ts: route('/blog', 'blog-custom.tsx')
import { createFileRoute } from '@tanstack/react-router';
import { Blog, type BlogPageProps } from '@salla.sa/twilight-theme-engine/routes/blog';
import { BlogSkeleton } from '@salla.sa/twilight-theme-engine/skeleton';
import { withHead } from '@salla.sa/twilight-theme-engine/tanstack';
export const Route = createFileRoute('/{-$locale}/blog')({
loader: ({ params }): Promise<BlogPageProps> =>
Blog.loader({ locale: params.locale }, (data) => ({ articles: data.articles.slice(0, 4) })),
head: withHead(Blog),
pendingComponent: () => <BlogSkeleton />,
component: BlogCustom,
});
function BlogCustom() {
const data: BlogPageProps = Route.useLoaderData();
return <Blog.Component {...data} />;
}
Example
import { createFileRoute } from '@tanstack/react-router';
import { Blog } from '@salla.sa/twilight-theme-engine/routes/blog';
import type { BlogPageProps } from '@salla.sa/twilight-theme-engine/routes/blog';
import { BlogSkeleton } from '@salla.sa/twilight-theme-engine/skeleton';
import { withHead } from '@salla.sa/twilight-theme-engine/tanstack';
export const Route = createFileRoute('/{-$locale}/blog')({
loader: ({ params }): Promise<BlogPageProps> => Blog.loader({ locale: params.locale }),
head: withHead(Blog),
pendingComponent: () => <BlogSkeleton />,
component: BlogComponent,
});
function BlogComponent() {
const data: BlogPageProps = Route.useLoaderData();
return <Blog.Component {...data} />;
}
How it behaves
URL:
/{-$locale}/blog, withBlogSkeletonas the pending component.blogLoaderreads the blog overview and builds the breadcrumbs Home › Blog. It takes no locale: the API language comes from the request.headsets the title and hreflang alternates, plus a description only whenpage.descriptionis set, which the loader never does.BlogPagerenders the slides in Salla's slider web component, the categories as a sidebar on large screens, the article cards, and the slotsblog:start,blog:items.start,blog:items.endandblog:end. With no slides it shows its own heading; with no slides and no articles,NoContent.There is no public blog API subpath. Outside a loader, read the blog with the API client:
api.get('blog').json()from@salla.sa/twilight-theme-engine/api/client, whose lists can benull(the demo shows how).Lazy: outside a route, wrap
BlogPagein<Suspense>.
Gotchas
blogLoadercatches every error and returns the page with emptyarticles,categories,slidesandpopular, without logging. A store without a blog and a failed request look the same: an empty blog. Check the network panel before assuming the blog is empty.
Related
One blog article with its related articles, likes and comments, using the article's own SEO title, description and image when set.
BlogAuthorRoute, BlogCategoryRoute, BlogTagRouteBlog article lists filtered by one author, one category or one tag, each with the category sidebar and more articles as the reader scrolls.
Blog data typesThe shapes of blog articles, authors, categories and tags that the blog loaders return, for typing your own blog components.
apiThe HTTP client behind every engine API module: ky, pointed at the Salla Store API, adding store, language, version, token and branch headers.
Source and docs
- Engine source:
packages/theme-engine/src/routes/blog/index.tsx