@geenius/blog
v0.17.0
Published
Geenius Blog — MDX-based blog system for SaaS apps (React + SolidJS)
Maintainers
Readme
@geenius/blog
A full-featured, framework-agnostic blog engine for Geenius applications:
MDX-first content authoring, CRUD-backed post storage, categories, tags,
search, reading stats, RSS/Atom feeds, SEO metadata, admin pages, and polished
UI across the active Geenius support matrix (react, react-css, solidjs,
solidjs-css) plus the four launch provider subpaths.
The parent @geenius/blog package is the only npm publisher; the framework
subpaths (/react, /react-css, /solidjs, etc.) and provider subpaths
(/convex, /neon, /cloudflareKV, /memory) are exposed as public
sub-paths off this single tarball.
Install
pnpm add @geenius/blog30-second quickstart (React + Tailwind)
import { BlogIndexPage, BlogProvider } from "@geenius/blog/react";
import type { BlogPost } from "@geenius/blog";
const posts: BlogPost[] = [
{
slug: "hello-world",
title: "Hello, world",
description: "First post.",
content: "Welcome to the blog.",
author: { name: "Mehdi" },
tags: ["intro"],
publishedAt: "2026-04-30T09:00:00Z",
readingTime: 1,
},
];
export function BlogRoute() {
return (
<BlogProvider>
<BlogIndexPage categories={[]} posts={posts} tags={[]} />
</BlogProvider>
);
}Prefer no Tailwind? Swap
@geenius/blog/reactfor@geenius/blog/react-cssand addimport "@geenius/blog/react-css/styles.css";.
Imports
import {
DEFAULT_CONFIG,
generateRSSFeed,
getBlogConfig,
type BlogPost,
} from "@geenius/blog";import { BlogIndexPage, PostDetailPage } from "@geenius/blog/react";
import { BlogIndexPage as BlogIndexPageCss } from "@geenius/blog/react-css";
import "@geenius/blog/react-css/styles.css";import { BlogIndexPage, PostDetailPage } from "@geenius/blog/solidjs";
import { BlogIndexPage as BlogIndexPageCss } from "@geenius/blog/solidjs-css";
import "@geenius/blog/solidjs-css/styles.css";import { componentDefinition, listPosts, publishPost } from "@geenius/blog/convex";Available subpaths:
@geenius/blogfor shared config, content helpers, feed helpers, errors, and types@geenius/blog/reactfor the Tailwind-based React component, hook, and page surface@geenius/blog/react-cssfor the vanilla-CSS React component and page surface@geenius/blog/solidjsfor the Tailwind-based SolidJS component, primitive, and page surface@geenius/blog/solidjs-cssfor the vanilla-CSS SolidJS component, primitive, and page surface@geenius/blog/react-nativefor native screens, components, and hook-compatible surfaces@geenius/blog/convexfor blog schema, tables, queries, and mutations@geenius/blog/neonfor Postgres-backed repository helpers and migrations@geenius/blog/cloudflareKVfor edge KV snapshots and taxonomy indexes@geenius/blog/memoryfor deterministic local, test, and Storybook stores
The remaining UI-library variants are declared in
variants.json with inScope: false and are deferred from
the current build, type-check, test, Storybook, Playwright, and coverage
matrices. React Native is launch-scoped and tracked separately in
scorecard.yaml while native-device verification matures.
Memory fixtures:
import {
createMemoryBlogStore,
DEFAULT_MEMORY_BLOG_POSTS,
resetMemoryBlogStore,
seedMemoryBlogStore,
} from "@geenius/blog/memory";
const store = createMemoryBlogStore(DEFAULT_MEMORY_BLOG_POSTS);
await seedMemoryBlogStore(store, [
{ ...DEFAULT_MEMORY_BLOG_POSTS[0], title: "Updated" },
]);
await resetMemoryBlogStore(store);Usage
import type { BlogPost, Category, Tag } from "@geenius/blog";
import { BlogIndexPage } from "@geenius/blog/react";
const posts: BlogPost[] = [
{
slug: "shipping-golden-packages",
title: "Shipping Golden Packages",
description: "How Geenius standardizes package families.",
content: "Story-driven package development matters.",
author: { name: "Mehdi Nabhani" },
category: "engineering",
tags: ["packaging", "typescript"],
publishedAt: "2026-04-12T09:00:00.000Z",
readingTime: 6,
},
];
const categories: Category[] = [
{
id: "engineering",
name: "Engineering",
slug: "engineering",
postCount: 1,
},
];
const tags: Tag[] = [
{
id: "packaging",
name: "Packaging",
slug: "packaging",
postCount: 1,
},
];
export function BlogScreen(): React.JSX.Element {
return <BlogIndexPage categories={categories} posts={posts} tags={tags} />;
}API Reference
The root @geenius/blog export contains shared post, taxonomy, validation, and
memory-store utilities. Framework entrypoints provide matching page and
component surfaces:
BlogIndexPagerenders the listing experience fromposts,categories, andtags; passpageSizewhen the listing should paginate non-featured posts instead of showing the default count.PostDetailPagerenders a normalizedBlogPostwith generated metadata, reading progress, related posts, and share actions.BlogProviderwires aBlogStoreimplementation into framework consumers when the package is used with a custom persistence layer.
See .docs/DOCS/PACKAGES/BLOG.md for the package architecture, launch scope, and variant parity expectations.
Storybook
The package includes one stock Storybook v10 application per in-scope UI variant. Use the registry-driven runner for normal development:
pnpm storybook -- --variant reactpnpm storybook -- --variant solidjs-csspnpm storybook:buildpnpm test:storybook
Each app consumes the public @geenius/blog/<variant> subpath and includes the
V2 .storybook/{main,manager,preview}.ts shape with mandatory Welcome and
Tokens stories.
Review variant app entrypoints:
Contributing tests
Add or change variants in variants.json first. Build, test, Storybook, size, coverage, and browser harness scripts read that file, so new variant coverage should be a registry change plus the variant source/app files. Do not add hardcoded variant arrays to scripts or configs.
Useful local gates:
pnpm test:gauntletpnpm test:allpnpm test:conventionspnpm test:exportspnpm test:db:conformancepnpm test:db:real(opt-in; requires a Docker-compatible container runtime for the Neon Testcontainers lane andGEENIUS_BLOG_CONVEX_URLpointing at a localconvex devbackend — not part ofpnpm test:all)pnpm test:e2epnpm test:a11ypnpm test:visualpnpm test:perfpnpm sizepnpm audit:supply-chainpnpm test:licensepnpm test:coveragepnpm test:coverage:diff
License
Commercial. See LICENSE.
