@m13v/seo-components 0.22.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/_build.css +5 -1
- package/src/components/ClaudeMeterCta.tsx +3 -2
- package/src/index.ts +2 -0
- package/src/lib/track.ts +42 -0
- package/src/server.ts +7 -4
- package/src/components/SeoComponentsStyles.tsx +0 -19
package/package.json
CHANGED
package/src/_build.css
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/* Build input for the prebuilt styles.css shipped in the npm package. */
|
|
2
2
|
/* This file is consumed by `tailwindcss -i src/_build.css -o dist/styles.css`. */
|
|
3
|
-
/*
|
|
3
|
+
/* Consumer apps should NOT import this source file. If you need the prebuilt
|
|
4
|
+
bundle, import the compiled artifact: `import "@m13v/seo-components/styles.css"`.
|
|
5
|
+
In most cases the right approach is to let your own Tailwind scan the
|
|
6
|
+
library via `@source "../../node_modules/@seo/components/src";` in
|
|
7
|
+
globals.css, which is how every current consumer does it. */
|
|
4
8
|
@tailwind base;
|
|
5
9
|
@tailwind components;
|
|
6
10
|
@tailwind utilities;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { motion } from "framer-motion";
|
|
4
|
-
import {
|
|
4
|
+
import { trackCrossProductClick } from "../lib/track";
|
|
5
5
|
|
|
6
6
|
export interface ClaudeMeterCtaProps {
|
|
7
7
|
/** Placement tag, kept in analytics payload. */
|
|
@@ -30,9 +30,10 @@ export function ClaudeMeterCta({
|
|
|
30
30
|
const sectionLabel = section ?? `claude-meter-cta-${placement}`;
|
|
31
31
|
|
|
32
32
|
const handleClick = () => {
|
|
33
|
-
|
|
33
|
+
trackCrossProductClick({
|
|
34
34
|
destination: href,
|
|
35
35
|
site,
|
|
36
|
+
targetProduct: "claude-meter",
|
|
36
37
|
section: sectionLabel,
|
|
37
38
|
text: "Install Claude Meter",
|
|
38
39
|
component: "ClaudeMeterCta",
|
package/src/index.ts
CHANGED
|
@@ -64,12 +64,14 @@ export {
|
|
|
64
64
|
trackScheduleClick,
|
|
65
65
|
trackGetStartedClick,
|
|
66
66
|
trackDownloadClick,
|
|
67
|
+
trackCrossProductClick,
|
|
67
68
|
withBookingAttribution,
|
|
68
69
|
} from "./lib/track";
|
|
69
70
|
export type {
|
|
70
71
|
ScheduleClickProps,
|
|
71
72
|
GetStartedClickProps,
|
|
72
73
|
DownloadClickProps,
|
|
74
|
+
CrossProductClickProps,
|
|
73
75
|
} from "./lib/track";
|
|
74
76
|
|
|
75
77
|
// Analytics context: provider + hooks so library components fire PostHog
|
package/src/lib/track.ts
CHANGED
|
@@ -145,3 +145,45 @@ export type DownloadClickProps = GetStartedClickProps;
|
|
|
145
145
|
export function trackDownloadClick(props: GetStartedClickProps): void {
|
|
146
146
|
trackGetStartedClick(props);
|
|
147
147
|
}
|
|
148
|
+
|
|
149
|
+
export interface CrossProductClickProps {
|
|
150
|
+
/** Absolute URL the click sends the user to (e.g. https://claude-meter.com/install). */
|
|
151
|
+
destination: string;
|
|
152
|
+
/** Slug of the ORIGIN site the click happened on (e.g. "fazm"). */
|
|
153
|
+
site?: string;
|
|
154
|
+
/** Slug of the DESTINATION product being promoted (e.g. "claude-meter"). */
|
|
155
|
+
targetProduct?: string;
|
|
156
|
+
/** Section of the page the CTA lives in (e.g. "blog-post-top", "blog-post-bottom"). */
|
|
157
|
+
section?: string;
|
|
158
|
+
/** Visible button/link text. */
|
|
159
|
+
text?: string;
|
|
160
|
+
/** Name of the rendering component (e.g. "ClaudeMeterCta"). */
|
|
161
|
+
component?: string;
|
|
162
|
+
/** Free-form extra properties — merged last, cannot override reserved keys above. */
|
|
163
|
+
extra?: Record<string, unknown>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Fire the canonical `cross_product_click` PostHog event. Use for every CTA
|
|
168
|
+
* that promotes a SIBLING product on a different site (e.g. a Claude Meter
|
|
169
|
+
* CTA on fazm.ai blog posts). These clicks are tracked separately from the
|
|
170
|
+
* primary `get_started_click` event so the dashboard can distinguish
|
|
171
|
+
* own-product conversions from cross-promotion.
|
|
172
|
+
*
|
|
173
|
+
* The dashboard at social-autoposter/scripts/project_stats_json.py counts
|
|
174
|
+
* this event per `$host` to produce the "Cross Product" column in the
|
|
175
|
+
* Project Funnel Stats table.
|
|
176
|
+
*/
|
|
177
|
+
export function trackCrossProductClick(props: CrossProductClickProps): void {
|
|
178
|
+
const { destination, site, targetProduct, section, text, component, extra } = props;
|
|
179
|
+
captureFromWindow("cross_product_click", {
|
|
180
|
+
...(extra || {}),
|
|
181
|
+
destination,
|
|
182
|
+
site,
|
|
183
|
+
target_product: targetProduct,
|
|
184
|
+
section,
|
|
185
|
+
text,
|
|
186
|
+
component,
|
|
187
|
+
page: typeof window !== "undefined" ? window.location.pathname : undefined,
|
|
188
|
+
});
|
|
189
|
+
}
|
package/src/server.ts
CHANGED
|
@@ -37,7 +37,10 @@ export { getSupabaseAdmin } from "./lib/supabase-admin";
|
|
|
37
37
|
export { createNewsletterHandler } from "./lib/newsletter-route";
|
|
38
38
|
export type { NewsletterConfig } from "./lib/newsletter-route";
|
|
39
39
|
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
40
|
+
// SeoComponentsStyles was removed in v0.23.0. It injected a prebuilt Tailwind
|
|
41
|
+
// bundle wrapped in `@layer seo-components`, which collided with the
|
|
42
|
+
// consumer's own `@layer utilities` and forced GuideChatPanel / SitemapSidebar
|
|
43
|
+
// to `display: none`. Consumers should rely on their own Tailwind scanning
|
|
44
|
+
// the library via `@source "../../node_modules/@seo/components/src";` in
|
|
45
|
+
// globals.css instead. The prebuilt CSS file is still shipped for anyone
|
|
46
|
+
// who wants to `import "@m13v/seo-components/styles.css"` directly.
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
|
|
5
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
const cssPath = path.join(here, "..", "..", "dist", "styles.css");
|
|
7
|
-
|
|
8
|
-
let cachedCss: string | null = null;
|
|
9
|
-
function loadCss(): string {
|
|
10
|
-
if (cachedCss !== null) return cachedCss;
|
|
11
|
-
const raw = fs.readFileSync(cssPath, "utf8");
|
|
12
|
-
cachedCss = `@layer seo-components { ${raw} }`;
|
|
13
|
-
return cachedCss;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function SeoComponentsStyles() {
|
|
17
|
-
const css = loadCss();
|
|
18
|
-
return <style dangerouslySetInnerHTML={{ __html: css }} />;
|
|
19
|
-
}
|