@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m13v/seo-components",
3
- "version": "0.22.1",
3
+ "version": "0.24.0",
4
4
  "scripts": {
5
5
  "build:css": "tailwind -i src/_build.css -o dist/styles.css --minify",
6
6
  "bump:consumers": "bash scripts/bump-consumers.sh",
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
- /* Do NOT import this file from a consumer app; use `@m13v/seo-components/server`'s SeoComponentsStyles. */
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 { trackGetStartedClick } from "../lib/track";
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
- trackGetStartedClick({
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
- // Style injector server-only component that inlines the prebuilt Tailwind
41
- // CSS for the sidebar/chat/heading components as a <style> tag.
42
- // Use in your root layout <head> to avoid consumer-side PostCSS conflicts.
43
- export { SeoComponentsStyles } from "./components/SeoComponentsStyles";
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
- }