release: 0.1.1 with Gemini 3.6 support and two blog posts (#44)

Co-authored-by: Alice <alice@prismshadow.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
authored and GitHub committed 2026-07-23 06:13:49 +08:00
1 parent 7617374d58
commit f3217dca4b
49 files changed
+2249 -47

No files matched your search

@@ -0,0 +1,60 @@
/**
* Raw-HTML rendering contract for post bodies, via react-dom/server static markup.
*
* Post bodies are first-party Markdown in this repo, so the blog renderer enables `rehype-raw`
* (see the boundary note on REHYPE_PLUGINS in src/pages/blog-post.tsx). These tests pin the two
* halves of that: the raw tags posts actually use become elements, and the surrounding Markdown
* still parses — a `<details>` body is separated from its tags by blank lines precisely so the
* fenced code inside it stays Markdown.
*/
import { describe, expect, it } from "vitest";
import { createElement } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import Markdown from "react-markdown";
import { REHYPE_PLUGINS, REMARK_PLUGINS } from "../src/pages/blog-post";
const render = (markdown: string) =>
renderToStaticMarkup(
createElement(
Markdown,
{ remarkPlugins: REMARK_PLUGINS, rehypePlugins: REHYPE_PLUGINS },
markdown,
),
);
const DETAILS = `<details>
<summary><strong>Expand: the layout</strong></summary>
\`\`\`text
benchmark_config.toml
\`\`\`
</details>
`;
describe("blog post raw HTML", () => {
it("renders <details>/<summary> as elements, not escaped text", () => {
const html = render(DETAILS);
expect(html).toContain("<details>");
expect(html).toContain("<summary><strong>Expand: the layout</strong></summary>");
expect(html).not.toContain("&lt;details&gt;");
});
it("keeps the Markdown inside a <details> body as Markdown", () => {
const html = render(DETAILS);
expect(html).toContain("<pre>");
expect(html).toContain("benchmark_config.toml");
});
it("renders the inline <img> attributes posts use", () => {
const html = render('<img width="491" height="481" alt="A screenshot" src="/a.png" />');
expect(html).toContain('alt="A screenshot"');
expect(html).toContain('width="491"');
expect(html).not.toContain("&lt;img");
});
it("still escapes angle brackets inside code spans", () => {
const html = render("Snapshots live at `snapshots/v<version>.tar.gz`.");
expect(html).toContain("<code>snapshots/v&lt;version&gt;.tar.gz</code>");
});
});
@@ -0,0 +1,60 @@
/**
* Blog post link rendering contract, via react-dom/server static markup (node env, no DOM):
* every link in a post body — explicit [text](url), bare autolinked URL (remark-gfm), relative
* or #anchor — opens in a new tab (target="_blank" + rel="noreferrer"), and the optional
* markdown link title survives the adapter's prop forwarding.
*/
import { describe, expect, it } from "vitest";
import { createElement } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import Markdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { MdLink } from "../src/pages/blog-post";
const render = (markdown: string) =>
renderToStaticMarkup(
createElement(Markdown, { remarkPlugins: [remarkGfm], components: { a: MdLink } }, markdown),
);
/** All rendered <a ...> opening tags. */
const anchors = (html: string) => html.match(/<a\b[^>]*>/g) ?? [];
const expectNewTab = (tag: string | undefined) => {
expect(tag).toContain('target="_blank"');
expect(tag).toContain('rel="noreferrer"');
};
describe("blog post links", () => {
it("external markdown links open in a new tab", () => {
const html = render("See [the source](https://blog.google/gemini) for the numbers.");
const tags = anchors(html);
expect(tags).toHaveLength(1);
expect(tags[0]).toContain('href="https://blog.google/gemini"');
expectNewTab(tags[0]);
expect(html).toContain(">the source</a>");
});
it("internal links open in a new tab too (unconditional, per the owner's ask)", () => {
const html = render("[practice post](/blog/natural-language-training-loop) and [top](#intro)");
const tags = anchors(html);
expect(tags).toHaveLength(2);
expect(tags[0]).toContain('href="/blog/natural-language-training-loop"');
for (const tag of tags) expectNewTab(tag);
});
it("bare autolinked URLs in CJK prose open in a new tab", () => {
const html = render("详见 https://example.com/a/very/long/path 的说明。");
const tags = anchors(html);
expect(tags).toHaveLength(1);
expect(tags[0]).toContain('href="https://example.com/a/very/long/path"');
expectNewTab(tags[0]);
});
it('preserves the markdown link title from [text](url "title")', () => {
const html = render('Read [docs](https://example.com "API docs") first.');
const tags = anchors(html);
expect(tags).toHaveLength(1);
expect(tags[0]).toContain('title="API docs"');
expectNewTab(tags[0]);
});
});
+18 -2
View File
@@ -96,19 +96,35 @@ describe("frontmatter mapping (author / pinned / category)", () => {
it("reads the pinned flag and sorts the pinned post first", () => {
for (const locale of ["en", "zh"] as const) {
const posts = postsFor(locale);
expect(posts.length).toBe(8);
expect(posts.length).toBe(10);
// The launch post stays the single pinned post; newer posts sort under it by date.
expect(posts.filter((p) => p.pinned).map((p) => p.slug)).toEqual([
"introducing-penguinharness",
]);
expect(posts[0]?.slug).toBe("introducing-penguinharness");
expect(posts[0]?.pinned).toBe(true);
// Pinning beats recency: the runner-up is strictly newer than the pinned post. Asserted
// as a relation rather than a slug, because the newest date is shared by several posts
// and the slug tie-break makes any single winner churn whenever a post is added.
expect(posts[1]!.date > posts[0]!.date).toBe(true);
}
});
it("filters by the practice category, newest first", () => {
expect(postsFor("en", "practice").map((p) => p.slug)).toEqual([
"natural-language-training-loop",
"penguin-harness-self-improvement-with-amd-gpu",
"local-agents-on-amd-gpus",
]);
});
it("filters by the news category, newest first", () => {
expect(postsFor("en", "news").map((p) => p.slug)).toEqual([
"introducing-penguinharness",
"gemini-3-6-in-penguinharness",
"fireworks-credits-amd",
]);
});
it("filters by the perspectives category", () => {
expect(postsFor("en", "perspectives").map((p) => p.slug)).toEqual([
// All three share 2026-07-22, so slug ascending is the tie-break.