Skip to content

Commit 456cbf9

Browse files
authored
fix(website): update blog developer day collection and add blog GA tracking (agentscope-ai#5758)
1 parent 150c1d9 commit 456cbf9

6 files changed

Lines changed: 121 additions & 70 deletions

File tree

website/public/blog/qwenpaw-developer-day-collection.en.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
---
22
title: "QwenPaw Developer Day Collection"
3-
date: 2026-07-01
3+
date: 2026-07-02
44
author: QwenPaw Team
55
tags: [QwenPaw, developer-day]
66
cover: /blog/qwenpaw-developer-day-collection-cover.png
77
excerpt: "Replay archive from QwenPaw developer day sessions — in-depth technical talks and practical insights for every QwenPaw developer and enthusiast."
88
---
99

10-
Last updated June 30, 2026
10+
Last updated July 2, 2026
1111

1212
---
1313

14+
**07-02 QwenPaw Developer Day: QwenPaw 2.0 Runtime Deep Dive**
15+
16+
Meeting link: https://shanji.dingtalk.com/app/transcribes/76327569643334393537303636305f323034353035363233375f30
17+
1418
**06-30 QwenPaw Developer Day: QwenPaw 2.0 Driver Deep Dive**
1519

1620
Meeting link: https://shanji.dingtalk.com/app/transcribes/76327569643334363335313437375f323034353035363233375f30

website/public/blog/qwenpaw-developer-day-collection.zh.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
---
22
title: "QwenPaw 开发者日会合集"
3-
date: 2026-06-30
3+
date: 2026-07-02
44
author: QwenPaw Team
55
tags: [QwenPaw, 日会合集]
66
cover: /blog/qwenpaw-developer-day-collection-cover.png
77
excerpt: "QwenPaw团队召开开发者日会,为每一位 QwenPaw 开发者与爱好者提供一份兼具理论深度与落地价值的完整技术交流档案。"
88
---
99

10-
最近更新 2026 年 630
10+
最近更新 2026 年 72
1111

1212
---
1313

14+
**07-02 QwenPaw 开发者日会:QwenPaw 2.0 Runtime 模块详解**
15+
16+
会议链接:https://shanji.dingtalk.com/app/transcribes/76327569643334393537303636305f323034353035363233375f30
17+
1418
**06-30 QwenPaw 开发者日会:QwenPaw 2.0 Driver 模块详解**
1519

1620
会议链接:https://shanji.dingtalk.com/app/transcribes/76327569643334363335313437375f323034353035363233375f30

website/src/App.tsx

Lines changed: 1 addition & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import { useTranslation } from "react-i18next";
44
import { loadSiteConfig, type SiteConfig, defaultConfig } from "@/config";
55
import { SiteConfigProvider } from "@/config-context";
66
import { SiteLayout } from "@/components/SiteLayout";
7+
import { GA_ID, loadGoogleAnalytics } from "@/lib/analytics";
78
import "@/index.css";
89

9-
const GA_ID = "G-BEX1XSB9KE";
10-
1110
// Lazy load page components for better performance
1211
const Home = lazy(() => import("@/pages/Home"));
1312
const Docs = lazy(() => import("@/pages/Docs"));
@@ -16,69 +15,6 @@ const BlogPost = lazy(() => import("@/pages/Blog/Post"));
1615
const ReleaseNotes = lazy(() => import("@/pages/ReleaseNotes"));
1716
const Downloads = lazy(() => import("@/pages/Downloads"));
1817

19-
declare global {
20-
interface Window {
21-
dataLayer: unknown[];
22-
gtag?: (...args: unknown[]) => void;
23-
}
24-
}
25-
26-
/**
27-
* Load Google Analytics script asynchronously
28-
* @param id - Google Analytics measurement ID
29-
*/
30-
function loadGoogleAnalytics(id: string) {
31-
// Skip if already loaded or in development
32-
if (window.gtag || import.meta.env.DEV) {
33-
if (import.meta.env.DEV) {
34-
console.log("[GA] Skipped in development environment");
35-
}
36-
return;
37-
}
38-
39-
console.log("[GA] Starting to load Google Analytics...");
40-
41-
// Initialize dataLayer
42-
window.dataLayer = window.dataLayer || [];
43-
function gtag(...args: unknown[]) {
44-
window.dataLayer.push(args);
45-
}
46-
window.gtag = gtag;
47-
48-
// Configure GA
49-
gtag("js", new Date());
50-
gtag("config", id);
51-
52-
// Load GA script with timeout protection
53-
const script = document.createElement("script");
54-
script.src = `https://www.googletagmanager.com/gtag/js?id=${id}`;
55-
script.async = true;
56-
57-
let isLoaded = false;
58-
const timeoutId = setTimeout(() => {
59-
if (!isLoaded) {
60-
console.warn("[GA] Load timeout - removing script");
61-
script.remove();
62-
delete window.gtag;
63-
}
64-
}, 6000);
65-
66-
script.onload = () => {
67-
isLoaded = true;
68-
clearTimeout(timeoutId);
69-
console.log("[GA] Loaded successfully");
70-
};
71-
72-
script.onerror = () => {
73-
isLoaded = true;
74-
clearTimeout(timeoutId);
75-
console.warn("[GA] Failed to load (may be blocked)");
76-
delete window.gtag;
77-
};
78-
79-
document.head.appendChild(script);
80-
}
81-
8218
/**
8319
* Initial loading fallback component
8420
*/
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
import { useEffect } from "react";
22
import { useLocation } from "react-router-dom";
3+
import { trackPageView } from "@/lib/analytics";
4+
5+
const BLOG_POST_PATH = /^\/blog\/[^/]+$/;
36

47
/** Reset window scroll on route change (SPA default keeps previous scroll position). */
58
export function ScrollToTop() {
6-
const { pathname, hash } = useLocation();
9+
const { pathname, hash, search } = useLocation();
710

811
useEffect(() => {
912
if (hash) return;
1013
window.scrollTo(0, 0);
1114
}, [pathname, hash]);
1215

16+
useEffect(() => {
17+
if (BLOG_POST_PATH.test(pathname)) return;
18+
trackPageView(`${pathname}${search}`);
19+
}, [pathname, search]);
20+
1321
return null;
1422
}

website/src/lib/analytics.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
export const GA_ID = "G-BEX1XSB9KE";
2+
3+
declare global {
4+
interface Window {
5+
dataLayer: unknown[];
6+
gtag?: (...args: unknown[]) => void;
7+
}
8+
}
9+
10+
/**
11+
* Load Google Analytics script asynchronously.
12+
* Skipped in development and when gtag is already present.
13+
*/
14+
export function loadGoogleAnalytics(id: string) {
15+
if (window.gtag || import.meta.env.DEV) {
16+
if (import.meta.env.DEV) {
17+
console.log("[GA] Skipped in development environment");
18+
}
19+
return;
20+
}
21+
22+
console.log("[GA] Starting to load Google Analytics...");
23+
24+
window.dataLayer = window.dataLayer || [];
25+
function gtag(...args: unknown[]) {
26+
window.dataLayer.push(args);
27+
}
28+
window.gtag = gtag;
29+
30+
gtag("js", new Date());
31+
gtag("config", id);
32+
33+
const script = document.createElement("script");
34+
script.src = `https://www.googletagmanager.com/gtag/js?id=${id}`;
35+
script.async = true;
36+
37+
let isLoaded = false;
38+
const timeoutId = setTimeout(() => {
39+
if (!isLoaded) {
40+
console.warn("[GA] Load timeout - removing script");
41+
script.remove();
42+
delete window.gtag;
43+
}
44+
}, 6000);
45+
46+
script.onload = () => {
47+
isLoaded = true;
48+
clearTimeout(timeoutId);
49+
console.log("[GA] Loaded successfully");
50+
};
51+
52+
script.onerror = () => {
53+
isLoaded = true;
54+
clearTimeout(timeoutId);
55+
console.warn("[GA] Failed to load (may be blocked)");
56+
delete window.gtag;
57+
};
58+
59+
document.head.appendChild(script);
60+
}
61+
62+
/** Report a SPA route change as a page view. */
63+
export function trackPageView(pagePath: string, pageTitle?: string) {
64+
if (!window.gtag) return;
65+
66+
window.gtag("config", GA_ID, {
67+
page_path: pagePath,
68+
...(pageTitle ? { page_title: pageTitle } : {}),
69+
});
70+
}
71+
72+
/** Record a blog article page view with article metadata. */
73+
export function trackBlogPostView(params: {
74+
slug: string;
75+
title: string;
76+
lang: string;
77+
}) {
78+
if (!window.gtag) return;
79+
80+
const pagePath = `/blog/${params.slug}`;
81+
82+
window.gtag("config", GA_ID, {
83+
page_path: pagePath,
84+
page_title: params.title,
85+
});
86+
87+
window.gtag("event", "blog_view", {
88+
blog_slug: params.slug,
89+
blog_title: params.title,
90+
blog_lang: params.lang,
91+
page_path: pagePath,
92+
});
93+
}

website/src/pages/Blog/Post.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
} from "@/lib/parseBlogMarkdown";
1616
import { MermaidBlock } from "@/components/MermaidBlock";
1717
import { ImageZoom } from "@/components/ImageZoom";
18+
import { trackBlogPostView } from "@/lib/analytics";
1819

1920
/** Turn plain "Meeting link: https://…" lines into markdown links for session lists. */
2021
function linkifySessionUrls(body: string): string {
@@ -82,6 +83,11 @@ export default function BlogPost() {
8283
setPost(null);
8384
} else {
8485
setPost(parsed);
86+
trackBlogPostView({
87+
slug,
88+
title: parsed.frontmatter.title,
89+
lang: isZh ? "zh" : "en",
90+
});
8591
}
8692
setLoading(false);
8793
});

0 commit comments

Comments
 (0)