blog umami fix
This commit is contained in:
@@ -3,9 +3,11 @@ import type { WordpressPost } from "../lib/content/types";
|
||||
|
||||
type Props = {
|
||||
post: WordpressPost;
|
||||
placement: string;
|
||||
targetId: string;
|
||||
};
|
||||
|
||||
const { post } = Astro.props;
|
||||
const { post, placement, targetId } = Astro.props;
|
||||
|
||||
function truncate(s: string, n: number) {
|
||||
if (!s) return "";
|
||||
@@ -15,11 +17,17 @@ function truncate(s: string, n: number) {
|
||||
}
|
||||
---
|
||||
|
||||
<a class="blog-card" href={`/blog/post/${post.slug}`}>
|
||||
<a
|
||||
class="blog-card"
|
||||
href={`/blog/post/${post.slug}`}
|
||||
data-umami-event="click"
|
||||
data-umami-event-target_id={targetId}
|
||||
data-umami-event-placement={placement}
|
||||
data-umami-event-target_url={`/blog/post/${post.slug}`}
|
||||
>
|
||||
{post.featuredImageUrl ? <img src={post.featuredImageUrl} alt="" loading="lazy" /> : null}
|
||||
<div class="blog-card-body">
|
||||
<h3 class="blog-card-title">{post.title}</h3>
|
||||
<p class="blog-card-excerpt">{truncate(post.excerpt || "", 180)}</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -10,16 +10,36 @@ const { categories, activeCategorySlug } = Astro.props;
|
||||
---
|
||||
|
||||
<nav class="subnav" aria-label="Blog categories">
|
||||
<a class={!activeCategorySlug ? "active" : ""} href="/blog">
|
||||
<a
|
||||
class={!activeCategorySlug ? "active" : ""}
|
||||
href="/blog"
|
||||
data-umami-event="click"
|
||||
data-umami-event-target_id="blog.subnav.all"
|
||||
data-umami-event-placement="blog.subnav"
|
||||
data-umami-event-target_url="/blog"
|
||||
>
|
||||
All
|
||||
</a>
|
||||
<a class={activeCategorySlug === "__pages" ? "active" : ""} href="/blog/pages">
|
||||
<a
|
||||
class={activeCategorySlug === "__pages" ? "active" : ""}
|
||||
href="/blog/pages"
|
||||
data-umami-event="click"
|
||||
data-umami-event-target_id="blog.subnav.pages"
|
||||
data-umami-event-placement="blog.subnav"
|
||||
data-umami-event-target_url="/blog/pages"
|
||||
>
|
||||
Pages
|
||||
</a>
|
||||
{categories.map((c) => (
|
||||
<a class={activeCategorySlug === c.slug ? "active" : ""} href={`/blog/category/${c.slug}`}>
|
||||
<a
|
||||
class={activeCategorySlug === c.slug ? "active" : ""}
|
||||
href={`/blog/category/${c.slug}`}
|
||||
data-umami-event="click"
|
||||
data-umami-event-target_id={`blog.subnav.category.${c.slug}`}
|
||||
data-umami-event-placement="blog.subnav"
|
||||
data-umami-event-target_url={`/blog/category/${c.slug}`}
|
||||
>
|
||||
{c.name}
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
|
||||
@@ -44,7 +44,11 @@ if (!activeCategory) {
|
||||
{posts.length > 0 ? (
|
||||
<div class="blog-grid">
|
||||
{posts.map((p) => (
|
||||
<BlogPostCard post={p} />
|
||||
<BlogPostCard
|
||||
post={p}
|
||||
placement={`blog.category.${activeCategory.slug}`}
|
||||
targetId={`blog.category.${activeCategory.slug}.card.post.${p.slug}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
|
||||
@@ -25,7 +25,7 @@ const pages = wordpressPages(cache);
|
||||
{posts.length > 0 ? (
|
||||
<div class="blog-grid">
|
||||
{posts.map((p) => (
|
||||
<BlogPostCard post={p} />
|
||||
<BlogPostCard post={p} placement="blog.index" targetId={`blog.index.card.post.${p.slug}`} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
@@ -37,18 +37,32 @@ const pages = wordpressPages(cache);
|
||||
<section class="section">
|
||||
<div class="section-header">
|
||||
<h2>Pages</h2>
|
||||
<a class="muted" href="/blog/pages">
|
||||
<a
|
||||
class="muted"
|
||||
href="/blog/pages"
|
||||
data-umami-event="click"
|
||||
data-umami-event-target_id="blog.index.pages.browse"
|
||||
data-umami-event-placement="blog.index.pages_preview"
|
||||
data-umami-event-target_url="/blog/pages"
|
||||
>
|
||||
Browse pages →
|
||||
</a>
|
||||
</div>
|
||||
<div class="empty">
|
||||
{pages.slice(0, 6).map((p) => (
|
||||
<div>
|
||||
<a href={`/blog/page/${p.slug}`}>{p.title}</a>
|
||||
<a
|
||||
href={`/blog/page/${p.slug}`}
|
||||
data-umami-event="click"
|
||||
data-umami-event-target_id={`blog.index.pages.link.${p.slug}`}
|
||||
data-umami-event-placement="blog.index.pages_preview"
|
||||
data-umami-event-target_url={`/blog/page/${p.slug}`}
|
||||
>
|
||||
{p.title}
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
) : null}
|
||||
</BlogLayout>
|
||||
|
||||
|
||||
@@ -33,7 +33,16 @@ const metaDescription = (page.excerpt || "").slice(0, 160);
|
||||
<section class="section">
|
||||
<div class="section-header">
|
||||
<h2 style="margin: 0;">{page.title}</h2>
|
||||
<a class="muted" href="/blog">Back →</a>
|
||||
<a
|
||||
class="muted"
|
||||
href="/blog"
|
||||
data-umami-event="click"
|
||||
data-umami-event-target_id="blog.page.back"
|
||||
data-umami-event-placement="blog.page"
|
||||
data-umami-event-target_url="/blog"
|
||||
>
|
||||
Back →
|
||||
</a>
|
||||
</div>
|
||||
{page.featuredImageUrl ? (
|
||||
<img
|
||||
@@ -46,4 +55,3 @@ const metaDescription = (page.excerpt || "").slice(0, 160);
|
||||
<div class="prose" set:html={page.contentHtml} />
|
||||
</section>
|
||||
</BlogLayout>
|
||||
|
||||
|
||||
@@ -25,7 +25,15 @@ const pages = wordpressPages(cache);
|
||||
<div class="empty">
|
||||
{pages.map((p) => (
|
||||
<div style="padding: 6px 0;">
|
||||
<a href={`/blog/page/${p.slug}`}>{p.title}</a>
|
||||
<a
|
||||
href={`/blog/page/${p.slug}`}
|
||||
data-umami-event="click"
|
||||
data-umami-event-target_id={`blog.pages.link.${p.slug}`}
|
||||
data-umami-event-placement="blog.pages.list"
|
||||
data-umami-event-target_url={`/blog/page/${p.slug}`}
|
||||
>
|
||||
{p.title}
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -34,4 +42,3 @@ const pages = wordpressPages(cache);
|
||||
)}
|
||||
</section>
|
||||
</BlogLayout>
|
||||
|
||||
|
||||
@@ -33,7 +33,16 @@ const metaDescription = (post.excerpt || "").slice(0, 160);
|
||||
<section class="section">
|
||||
<div class="section-header">
|
||||
<h2 style="margin: 0;">{post.title}</h2>
|
||||
<a class="muted" href="/blog">Back →</a>
|
||||
<a
|
||||
class="muted"
|
||||
href="/blog"
|
||||
data-umami-event="click"
|
||||
data-umami-event-target_id="blog.post.back"
|
||||
data-umami-event-placement="blog.post"
|
||||
data-umami-event-target_url="/blog"
|
||||
>
|
||||
Back →
|
||||
</a>
|
||||
</div>
|
||||
<p class="muted" style="margin-top: 0;">
|
||||
{new Date(post.publishedAt).toLocaleDateString()}
|
||||
@@ -49,4 +58,3 @@ const metaDescription = (post.excerpt || "").slice(0, 160);
|
||||
<div class="prose" set:html={post.contentHtml} />
|
||||
</section>
|
||||
</BlogLayout>
|
||||
|
||||
|
||||
64
site/tests/blog-umami-attributes.test.ts
Normal file
64
site/tests/blog-umami-attributes.test.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { readFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
async function read(rel: string) {
|
||||
return await readFile(path.join(process.cwd(), rel), "utf8");
|
||||
}
|
||||
|
||||
describe("blog umami event attributes", () => {
|
||||
it("instruments blog secondary nav links", async () => {
|
||||
const src = await read("src/components/BlogSecondaryNav.astro");
|
||||
|
||||
expect(src).toContain('data-umami-event="click"');
|
||||
expect(src).toContain('data-umami-event-target_id="blog.subnav.all"');
|
||||
expect(src).toContain('data-umami-event-target_id="blog.subnav.pages"');
|
||||
expect(src).toContain("data-umami-event-target_id={`blog.subnav.category.${c.slug}`}");
|
||||
expect(src).toContain('data-umami-event-placement="blog.subnav"');
|
||||
expect(src).toContain("data-umami-event-target_url");
|
||||
});
|
||||
|
||||
it("instruments blog post cards with deterministic target_id and placement", async () => {
|
||||
const src = await read("src/components/BlogPostCard.astro");
|
||||
|
||||
expect(src).toContain('data-umami-event="click"');
|
||||
expect(src).toContain("data-umami-event-target_id={targetId}");
|
||||
expect(src).toContain("data-umami-event-placement={placement}");
|
||||
expect(src).toContain("data-umami-event-target_url");
|
||||
});
|
||||
|
||||
it("instruments blog pages list links (and keeps distinct IDs per placement)", async () => {
|
||||
const indexSrc = await read("src/pages/blog/index.astro");
|
||||
expect(indexSrc).toContain('data-umami-event-target_id="blog.index.pages.browse"');
|
||||
expect(indexSrc).toContain("data-umami-event-target_id={`blog.index.pages.link.${p.slug}`}");
|
||||
expect(indexSrc).toContain('data-umami-event-placement="blog.index.pages_preview"');
|
||||
|
||||
const pagesSrc = await read("src/pages/blog/pages.astro");
|
||||
expect(pagesSrc).toContain("data-umami-event-target_id={`blog.pages.link.${p.slug}`}");
|
||||
expect(pagesSrc).toContain('data-umami-event-placement="blog.pages.list"');
|
||||
});
|
||||
|
||||
it("instruments blog detail back links", async () => {
|
||||
const postSrc = await read("src/pages/blog/post/[slug].astro");
|
||||
expect(postSrc).toContain('data-umami-event-target_id="blog.post.back"');
|
||||
expect(postSrc).toContain('data-umami-event-placement="blog.post"');
|
||||
expect(postSrc).toContain('data-umami-event-target_url="/blog"');
|
||||
|
||||
const pageSrc = await read("src/pages/blog/page/[slug].astro");
|
||||
expect(pageSrc).toContain('data-umami-event-target_id="blog.page.back"');
|
||||
expect(pageSrc).toContain('data-umami-event-placement="blog.page"');
|
||||
expect(pageSrc).toContain('data-umami-event-target_url="/blog"');
|
||||
});
|
||||
|
||||
it("uses placement-specific target_id for post cards", async () => {
|
||||
const indexSrc = await read("src/pages/blog/index.astro");
|
||||
expect(indexSrc).toContain("targetId={`blog.index.card.post.${p.slug}`}");
|
||||
expect(indexSrc).toContain('placement="blog.index"');
|
||||
|
||||
const categorySrc = await read("src/pages/blog/category/[slug].astro");
|
||||
expect(categorySrc).toContain("placement={`blog.category.${activeCategory.slug}`}");
|
||||
expect(categorySrc).toContain("targetId={`blog.category.${activeCategory.slug}.card.post.${p.slug}`}");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user