@masters-ws/react-seo 1.4.3 → 1.5.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/README.md CHANGED
@@ -18,6 +18,7 @@ Professional high-performance SEO package for React and Next.js. **Zero-dependen
18
18
  - ✅ **i18n Ready** — No hardcoded strings, all labels are configurable
19
19
  - ✅ **Multilingual Support** — Easy `hreflang` management
20
20
  - ✅ **Performance Optimized** — DNS Prefetch, Preconnect, Preload support
21
+ - ✅ **SEO Auditor** — Real-time analysis & preview sidebar (Dev-only)
21
22
 
22
23
  ## Installation
23
24
 
@@ -33,6 +34,35 @@ npm install @masters-ws/react-seo react-helmet-async
33
34
 
34
35
  ---
35
36
 
37
+ ## 🔍 SEO Auditor (Development Only)
38
+
39
+ Boost your productivity with the built-in **SEO Auditor**. It provides a real-time analysis of your page's SEO health and shows a live preview of how your page looks in Google search results and social media cards.
40
+
41
+ - **Developer Friendly:** Only renders when `process.env.NODE_ENV === 'development'`.
42
+ - **Live Previews:** See exactly how Google and social platforms see your content.
43
+ - **Audit Checklist:** Instant feedback on title length, description, H1 count, alt tags, and more.
44
+ - **Zero Configuration:** Just drop it into your root layout.
45
+
46
+ ### Usage:
47
+
48
+ ```tsx
49
+ // app/layout.tsx (Next.js App Router)
50
+ import { SEOAuditor } from '@masters-ws/react-seo';
51
+
52
+ export default function RootLayout({ children }) {
53
+ return (
54
+ <html>
55
+ <body>
56
+ {children}
57
+ <SEOAuditor />
58
+ </body>
59
+ </html>
60
+ );
61
+ }
62
+ ```
63
+
64
+ ---
65
+
36
66
  ## 🚀 Quick Start: Next.js App Router (Recommended)
37
67
 
38
68
  ### Product Page (One-Call Setup)
@@ -1463,13 +1493,17 @@ interface SEOData {
1463
1493
 
1464
1494
  ---
1465
1495
 
1466
- ## 💙 Affiliate Program
1496
+ ## 💙 Recommended: Outrank — AI-Powered SEO Platform
1497
+
1498
+ Take your SEO to the next level with [**Outrank**](https://outrank.so/?via=shadi) — the AI-powered platform for creating SEO-optimized content at scale.
1499
+
1500
+ - 🚀 **AI Content Generation** — Blog posts, landing pages & more
1501
+ - 📊 **SEO Analysis** — Real-time optimization suggestions
1502
+ - ⚡ **Works great with this package** — Generate content, we handle the technical SEO
1467
1503
 
1468
- Love this package? Join the **Outrank Affiliate Program** and earn **30% lifetime recurring commission** on every referral!
1504
+ 🎁 **Exclusive:** Use code **`SHADI`** for **10% off** your first month.
1469
1505
 
1470
- 1. **Join here:** [Outrank Affiliate Program](https://outrank.so/?via=shadi)
1471
- 2. **Earn:** 30% commission for the lifetime of the customer.
1472
- 3. **Bonus:** Use coupon code **`SHADI`** for **10% off** on all payments within the first month for your friends.
1506
+ > Want to earn too? [Join the affiliate program](https://outrank.so/?via=shadi) — **30% lifetime recurring commission**.
1473
1507
 
1474
1508
  ---
1475
1509
 
package/dist/index.d.mts CHANGED
@@ -278,4 +278,6 @@ interface SeoJobPostingProps {
278
278
  }
279
279
  declare const SeoJobPosting: React.FC<SeoJobPostingProps>;
280
280
 
281
- export { Breadcrumb, BreadcrumbItem, type BreadcrumbProps, type FAQItem, type HowToStep, SEO, SEOData, type SEOProps, SEOProvider, type SEOProviderProps, SeoArticle, type SeoArticleProps, SeoAuthor, type SeoAuthorProps, SeoCategory, type SeoCategoryProps, SeoCourse, type SeoCourseProps, SeoEvent, type SeoEventProps, SeoFAQ, type SeoFAQProps, SeoHowTo, type SeoHowToProps, SeoJobPosting, type SeoJobPostingProps, SeoLocalBusiness, type SeoLocalBusinessProps, SeoProduct, type SeoProductProps, SeoRecipe, type SeoRecipeProps, SeoReview, type SeoReviewProps, SeoTag, type SeoTagProps, SeoVideo, type SeoVideoProps, SiteConfig, useSEOConfig };
281
+ declare const SEOAuditor: React.FC;
282
+
283
+ export { Breadcrumb, BreadcrumbItem, type BreadcrumbProps, type FAQItem, type HowToStep, SEO, SEOAuditor, SEOData, type SEOProps, SEOProvider, type SEOProviderProps, SeoArticle, type SeoArticleProps, SeoAuthor, type SeoAuthorProps, SeoCategory, type SeoCategoryProps, SeoCourse, type SeoCourseProps, SeoEvent, type SeoEventProps, SeoFAQ, type SeoFAQProps, SeoHowTo, type SeoHowToProps, SeoJobPosting, type SeoJobPostingProps, SeoLocalBusiness, type SeoLocalBusinessProps, SeoProduct, type SeoProductProps, SeoRecipe, type SeoRecipeProps, SeoReview, type SeoReviewProps, SeoTag, type SeoTagProps, SeoVideo, type SeoVideoProps, SiteConfig, useSEOConfig };
package/dist/index.d.ts CHANGED
@@ -278,4 +278,6 @@ interface SeoJobPostingProps {
278
278
  }
279
279
  declare const SeoJobPosting: React.FC<SeoJobPostingProps>;
280
280
 
281
- export { Breadcrumb, BreadcrumbItem, type BreadcrumbProps, type FAQItem, type HowToStep, SEO, SEOData, type SEOProps, SEOProvider, type SEOProviderProps, SeoArticle, type SeoArticleProps, SeoAuthor, type SeoAuthorProps, SeoCategory, type SeoCategoryProps, SeoCourse, type SeoCourseProps, SeoEvent, type SeoEventProps, SeoFAQ, type SeoFAQProps, SeoHowTo, type SeoHowToProps, SeoJobPosting, type SeoJobPostingProps, SeoLocalBusiness, type SeoLocalBusinessProps, SeoProduct, type SeoProductProps, SeoRecipe, type SeoRecipeProps, SeoReview, type SeoReviewProps, SeoTag, type SeoTagProps, SeoVideo, type SeoVideoProps, SiteConfig, useSEOConfig };
281
+ declare const SEOAuditor: React.FC;
282
+
283
+ export { Breadcrumb, BreadcrumbItem, type BreadcrumbProps, type FAQItem, type HowToStep, SEO, SEOAuditor, SEOData, type SEOProps, SEOProvider, type SEOProviderProps, SeoArticle, type SeoArticleProps, SeoAuthor, type SeoAuthorProps, SeoCategory, type SeoCategoryProps, SeoCourse, type SeoCourseProps, SeoEvent, type SeoEventProps, SeoFAQ, type SeoFAQProps, SeoHowTo, type SeoHowToProps, SeoJobPosting, type SeoJobPostingProps, SeoLocalBusiness, type SeoLocalBusinessProps, SeoProduct, type SeoProductProps, SeoRecipe, type SeoRecipeProps, SeoReview, type SeoReviewProps, SeoTag, type SeoTagProps, SeoVideo, type SeoVideoProps, SiteConfig, useSEOConfig };
package/dist/index.js CHANGED
@@ -187,6 +187,7 @@ __export(index_exports, {
187
187
  Breadcrumb: () => Breadcrumb,
188
188
  JsonLd: () => JsonLd,
189
189
  SEO: () => SEO,
190
+ SEOAuditor: () => SEOAuditor,
190
191
  SEOProvider: () => SEOProvider,
191
192
  SeoArticle: () => SeoArticle,
192
193
  SeoAuthor: () => SeoAuthor,
@@ -2588,11 +2589,223 @@ var SeoJobPosting = ({ job }) => {
2588
2589
  };
2589
2590
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Helmet, { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("script", { type: "application/ld+json", children: JSON.stringify(schema) }) });
2590
2591
  };
2592
+
2593
+ // src/components/SEOAuditor.tsx
2594
+ var import_react6 = require("react");
2595
+ var import_jsx_runtime19 = require("react/jsx-runtime");
2596
+ var COLORS = {
2597
+ primary: "#0061e0",
2598
+ success: "#008a00",
2599
+ warning: "#ea4335",
2600
+ bg: "#ffffff",
2601
+ text: "#202124",
2602
+ muted: "#70757a",
2603
+ border: "#dadce0"
2604
+ };
2605
+ var SEOAuditor = () => {
2606
+ const isDev = typeof process !== "undefined" && process.env.NODE_ENV === "development";
2607
+ const [isOpen, setIsOpen] = (0, import_react6.useState)(false);
2608
+ const [data, setData] = (0, import_react6.useState)({
2609
+ title: "",
2610
+ description: "",
2611
+ ogImage: "",
2612
+ ogTitle: "",
2613
+ ogDescription: "",
2614
+ h1Count: 0,
2615
+ imgWithoutAlt: 0,
2616
+ canonical: ""
2617
+ });
2618
+ (0, import_react6.useEffect)(() => {
2619
+ if (!isDev || typeof document === "undefined") return;
2620
+ const analyze = () => {
2621
+ setData({
2622
+ title: document.title,
2623
+ description: document.querySelector('meta[name="description"]')?.getAttribute("content") || "",
2624
+ ogImage: document.querySelector('meta[property="og:image"]')?.getAttribute("content") || "",
2625
+ ogTitle: document.querySelector('meta[property="og:title"]')?.getAttribute("content") || "",
2626
+ ogDescription: document.querySelector('meta[property="og:description"]')?.getAttribute("content") || "",
2627
+ h1Count: document.querySelectorAll("h1").length,
2628
+ imgWithoutAlt: Array.from(document.querySelectorAll("img")).filter((img) => !img.getAttribute("alt")).length,
2629
+ canonical: document.querySelector('link[rel="canonical"]')?.getAttribute("href") || ""
2630
+ });
2631
+ };
2632
+ analyze();
2633
+ const observer = new MutationObserver(analyze);
2634
+ observer.observe(document.head, { subtree: true, childList: true, attributes: true });
2635
+ window.addEventListener("focus", analyze);
2636
+ return () => {
2637
+ window.removeEventListener("focus", analyze);
2638
+ observer.disconnect();
2639
+ };
2640
+ }, [isDev]);
2641
+ if (!isDev) return null;
2642
+ const issues = [];
2643
+ if (!data.title) issues.push("Title is missing");
2644
+ else if (data.title.length < 30) issues.push("Title is too short (min 30 chars recommended)");
2645
+ else if (data.title.length > 60) issues.push("Title is too long (max 60 chars recommended)");
2646
+ if (!data.description) issues.push("Meta description is missing");
2647
+ else if (data.description.length < 120) issues.push("Description is too short (min 120 chars recommended)");
2648
+ else if (data.description.length > 160) issues.push("Description is too long (max 160 chars recommended)");
2649
+ if (data.h1Count !== 1) issues.push(`Found ${data.h1Count} H1 tags (should be exactly 1)`);
2650
+ if (data.imgWithoutAlt > 0) issues.push(`${data.imgWithoutAlt} images missing alt attributes`);
2651
+ if (!data.ogImage) issues.push("OpenGraph image missing for social sharing");
2652
+ const score = Math.max(0, 100 - issues.length * 15);
2653
+ const styles = {
2654
+ button: {
2655
+ position: "fixed",
2656
+ bottom: "20px",
2657
+ right: "20px",
2658
+ width: "56px",
2659
+ height: "56px",
2660
+ borderRadius: "28px",
2661
+ background: isOpen ? COLORS.warning : COLORS.primary,
2662
+ color: "white",
2663
+ display: "flex",
2664
+ alignItems: "center",
2665
+ justifyContent: "center",
2666
+ cursor: "pointer",
2667
+ boxShadow: "0 4px 16px rgba(0,0,0,0.2)",
2668
+ zIndex: 9999999,
2669
+ border: "none",
2670
+ fontSize: "24px",
2671
+ transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
2672
+ outline: "none",
2673
+ padding: 0
2674
+ },
2675
+ sidebar: {
2676
+ position: "fixed",
2677
+ top: 0,
2678
+ right: isOpen ? 0 : "-420px",
2679
+ width: "380px",
2680
+ height: "100vh",
2681
+ background: COLORS.bg,
2682
+ boxShadow: "-4px 0 24px rgba(0,0,0,0.15)",
2683
+ zIndex: 9999998,
2684
+ transition: "right 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
2685
+ overflowY: "auto",
2686
+ padding: "0",
2687
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
2688
+ color: COLORS.text,
2689
+ textAlign: "left"
2690
+ },
2691
+ header: {
2692
+ padding: "24px",
2693
+ background: COLORS.primary,
2694
+ color: "white",
2695
+ position: "sticky",
2696
+ top: 0,
2697
+ zIndex: 10
2698
+ },
2699
+ headerTitle: { fontSize: "20px", fontWeight: "bold", margin: "0 0 4px 0", display: "flex", alignItems: "center", gap: "8px" },
2700
+ headerSubtitle: { fontSize: "13px", opacity: 0.8 },
2701
+ content: { padding: "24px" },
2702
+ scoreContainer: { textAlign: "center", marginBottom: "24px" },
2703
+ scoreText: {
2704
+ fontSize: "56px",
2705
+ fontWeight: "bold",
2706
+ color: score > 80 ? COLORS.success : score > 50 ? "#f4b400" : COLORS.warning,
2707
+ lineHeight: "1"
2708
+ },
2709
+ section: { marginTop: "24px", borderTop: `1px solid ${COLORS.border}`, paddingTop: "20px" },
2710
+ sectionTitle: { fontSize: "13px", fontWeight: "bold", textTransform: "uppercase", color: COLORS.muted, marginBottom: "12px", letterSpacing: "0.05em" },
2711
+ googlePreview: { background: "white", padding: "16px", border: `1px solid ${COLORS.border}`, borderRadius: "12px", boxShadow: "0 2px 6px rgba(0,0,0,0.05)" },
2712
+ googleTitle: { color: "#1a0dab", fontSize: "20px", marginBottom: "4px", textDecoration: "none", display: "block", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
2713
+ googleUrl: { color: "#202124", fontSize: "14px", marginBottom: "4px", display: "block" },
2714
+ googleDesc: { color: "#4d5156", fontSize: "14px", lineHeight: "1.58" },
2715
+ socialPreview: { background: "white", border: `1px solid ${COLORS.border}`, borderRadius: "12px", overflow: "hidden", boxShadow: "0 2px 6px rgba(0,0,0,0.05)" },
2716
+ socialImage: { width: "100%", aspectRatio: "1.91/1", background: "#f5f5f5", display: "flex", alignItems: "center", justifyContent: "center", overflow: "hidden" },
2717
+ socialContent: { padding: "12px", background: "#f0f2f5", borderTop: `1px solid ${COLORS.border}` },
2718
+ issue: { background: "#fff1f0", padding: "10px 14px", borderRadius: "6px", marginBottom: "10px", fontSize: "13px", color: "#cf1322", border: "1px solid #ffa39e", display: "flex", alignItems: "flex-start", gap: "8px" },
2719
+ successItem: { background: "#f6ffed", padding: "10px 14px", borderRadius: "6px", marginBottom: "10px", fontSize: "13px", color: "#389e0d", border: "1px solid #b7eb8f", display: "flex", alignItems: "flex-start", gap: "8px" },
2720
+ footer: { marginTop: "32px", padding: "16px", background: "#f8f9fa", borderRadius: "12px", fontSize: "12px", color: COLORS.muted, border: `1px solid ${COLORS.border}` }
2721
+ };
2722
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
2723
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2724
+ "button",
2725
+ {
2726
+ style: styles.button,
2727
+ onClick: () => setIsOpen(!isOpen),
2728
+ title: isOpen ? "Close Auditor" : "Open SEO Auditor",
2729
+ children: isOpen ? "\u2715" : "\u{1F50D}"
2730
+ }
2731
+ ),
2732
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.sidebar, children: [
2733
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.header, children: [
2734
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.headerTitle, children: [
2735
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "\u{1F4CA}" }),
2736
+ " SEO Auditor"
2737
+ ] }),
2738
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: styles.headerSubtitle, children: "Real-time analysis & preview" })
2739
+ ] }),
2740
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.content, children: [
2741
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.scoreContainer, children: [
2742
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.scoreText, children: [
2743
+ score,
2744
+ "%"
2745
+ ] }),
2746
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { color: COLORS.muted, fontSize: "14px", marginTop: "4px" }, children: "Page SEO Score" })
2747
+ ] }),
2748
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.section, children: [
2749
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: styles.sectionTitle, children: "Google Search Result" }),
2750
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.googlePreview, children: [
2751
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: styles.googleTitle, children: data.title || "Add Page Title" }),
2752
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: styles.googleUrl, children: typeof window !== "undefined" ? data.canonical || window.location.href : "" }),
2753
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: styles.googleDesc, children: data.description || "\u26A0\uFE0F Pro Tip: Add a meta description between 120-160 characters to improve search standing." })
2754
+ ] })
2755
+ ] }),
2756
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.section, children: [
2757
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: styles.sectionTitle, children: "Social Media Preview" }),
2758
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.socialPreview, children: [
2759
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: styles.socialImage, children: data.ogImage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("img", { src: data.ogImage, alt: "Social preview", style: { width: "100%", height: "100%", objectFit: "cover" } }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { color: COLORS.muted, textAlign: "center", padding: "20px" }, children: "\u{1F4F7} No OG image found" }) }),
2760
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.socialContent, children: [
2761
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { color: COLORS.muted, fontSize: "11px", textTransform: "uppercase", marginBottom: "2px" }, children: typeof window !== "undefined" ? window.location.hostname : "" }),
2762
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { fontWeight: "bold", fontSize: "15px", color: COLORS.text, marginBottom: "4px", overflow: "hidden", textOverflow: "ellipsis", display: "-webkit-box", WebkitLineClamp: "2", WebkitBoxOrient: "vertical" }, children: data.ogTitle || data.title || "No Social Title" }),
2763
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { fontSize: "13px", color: COLORS.muted, overflow: "hidden", textOverflow: "ellipsis", display: "-webkit-box", WebkitLineClamp: "2", WebkitBoxOrient: "vertical" }, children: data.ogDescription || data.description || "No summary available." })
2764
+ ] })
2765
+ ] })
2766
+ ] }),
2767
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.section, children: [
2768
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: styles.sectionTitle, children: "SEO Audit Checklist" }),
2769
+ issues.length > 0 ? issues.map((issue, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.issue, children: [
2770
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { fontWeight: "bold" }, children: "\u274C" }),
2771
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: issue })
2772
+ ] }, i)) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.successItem, children: [
2773
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { fontWeight: "bold" }, children: "\u2705" }),
2774
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "All structural checks passed! Excellent work." })
2775
+ ] }),
2776
+ data.h1Count === 1 && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.successItem, children: [
2777
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "\u2705" }),
2778
+ " Found exactly one H1 tag"
2779
+ ] }),
2780
+ data.imgWithoutAlt === 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.successItem, children: [
2781
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "\u2705" }),
2782
+ " All images have alt attributes"
2783
+ ] }),
2784
+ data.canonical && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.successItem, children: [
2785
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "\u2705" }),
2786
+ " Canonical link is defined"
2787
+ ] })
2788
+ ] }),
2789
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: styles.footer, children: [
2790
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("strong", { children: "\u{1F4A1} Pro Tip:" }),
2791
+ " Use ",
2792
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("code", { children: "generateArticleMetadata()" }),
2793
+ " or ",
2794
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("code", { children: "generateProductMetadata()" }),
2795
+ " from ",
2796
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("code", { children: "@masters-ws/react-seo/core" }),
2797
+ " for one-call professional SEO setup in Next.js."
2798
+ ] })
2799
+ ] })
2800
+ ] })
2801
+ ] });
2802
+ };
2591
2803
  // Annotate the CommonJS export names for ESM import in node:
2592
2804
  0 && (module.exports = {
2593
2805
  Breadcrumb,
2594
2806
  JsonLd,
2595
2807
  SEO,
2808
+ SEOAuditor,
2596
2809
  SEOProvider,
2597
2810
  SeoArticle,
2598
2811
  SeoAuthor,
package/dist/index.mjs CHANGED
@@ -1581,10 +1581,222 @@ var SeoJobPosting = ({ job }) => {
1581
1581
  };
1582
1582
  return /* @__PURE__ */ jsx17(Helmet, { children: /* @__PURE__ */ jsx17("script", { type: "application/ld+json", children: JSON.stringify(schema) }) });
1583
1583
  };
1584
+
1585
+ // src/components/SEOAuditor.tsx
1586
+ import { useState, useEffect } from "react";
1587
+ import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs3 } from "react/jsx-runtime";
1588
+ var COLORS = {
1589
+ primary: "#0061e0",
1590
+ success: "#008a00",
1591
+ warning: "#ea4335",
1592
+ bg: "#ffffff",
1593
+ text: "#202124",
1594
+ muted: "#70757a",
1595
+ border: "#dadce0"
1596
+ };
1597
+ var SEOAuditor = () => {
1598
+ const isDev = typeof process !== "undefined" && process.env.NODE_ENV === "development";
1599
+ const [isOpen, setIsOpen] = useState(false);
1600
+ const [data, setData] = useState({
1601
+ title: "",
1602
+ description: "",
1603
+ ogImage: "",
1604
+ ogTitle: "",
1605
+ ogDescription: "",
1606
+ h1Count: 0,
1607
+ imgWithoutAlt: 0,
1608
+ canonical: ""
1609
+ });
1610
+ useEffect(() => {
1611
+ if (!isDev || typeof document === "undefined") return;
1612
+ const analyze = () => {
1613
+ setData({
1614
+ title: document.title,
1615
+ description: document.querySelector('meta[name="description"]')?.getAttribute("content") || "",
1616
+ ogImage: document.querySelector('meta[property="og:image"]')?.getAttribute("content") || "",
1617
+ ogTitle: document.querySelector('meta[property="og:title"]')?.getAttribute("content") || "",
1618
+ ogDescription: document.querySelector('meta[property="og:description"]')?.getAttribute("content") || "",
1619
+ h1Count: document.querySelectorAll("h1").length,
1620
+ imgWithoutAlt: Array.from(document.querySelectorAll("img")).filter((img) => !img.getAttribute("alt")).length,
1621
+ canonical: document.querySelector('link[rel="canonical"]')?.getAttribute("href") || ""
1622
+ });
1623
+ };
1624
+ analyze();
1625
+ const observer = new MutationObserver(analyze);
1626
+ observer.observe(document.head, { subtree: true, childList: true, attributes: true });
1627
+ window.addEventListener("focus", analyze);
1628
+ return () => {
1629
+ window.removeEventListener("focus", analyze);
1630
+ observer.disconnect();
1631
+ };
1632
+ }, [isDev]);
1633
+ if (!isDev) return null;
1634
+ const issues = [];
1635
+ if (!data.title) issues.push("Title is missing");
1636
+ else if (data.title.length < 30) issues.push("Title is too short (min 30 chars recommended)");
1637
+ else if (data.title.length > 60) issues.push("Title is too long (max 60 chars recommended)");
1638
+ if (!data.description) issues.push("Meta description is missing");
1639
+ else if (data.description.length < 120) issues.push("Description is too short (min 120 chars recommended)");
1640
+ else if (data.description.length > 160) issues.push("Description is too long (max 160 chars recommended)");
1641
+ if (data.h1Count !== 1) issues.push(`Found ${data.h1Count} H1 tags (should be exactly 1)`);
1642
+ if (data.imgWithoutAlt > 0) issues.push(`${data.imgWithoutAlt} images missing alt attributes`);
1643
+ if (!data.ogImage) issues.push("OpenGraph image missing for social sharing");
1644
+ const score = Math.max(0, 100 - issues.length * 15);
1645
+ const styles = {
1646
+ button: {
1647
+ position: "fixed",
1648
+ bottom: "20px",
1649
+ right: "20px",
1650
+ width: "56px",
1651
+ height: "56px",
1652
+ borderRadius: "28px",
1653
+ background: isOpen ? COLORS.warning : COLORS.primary,
1654
+ color: "white",
1655
+ display: "flex",
1656
+ alignItems: "center",
1657
+ justifyContent: "center",
1658
+ cursor: "pointer",
1659
+ boxShadow: "0 4px 16px rgba(0,0,0,0.2)",
1660
+ zIndex: 9999999,
1661
+ border: "none",
1662
+ fontSize: "24px",
1663
+ transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
1664
+ outline: "none",
1665
+ padding: 0
1666
+ },
1667
+ sidebar: {
1668
+ position: "fixed",
1669
+ top: 0,
1670
+ right: isOpen ? 0 : "-420px",
1671
+ width: "380px",
1672
+ height: "100vh",
1673
+ background: COLORS.bg,
1674
+ boxShadow: "-4px 0 24px rgba(0,0,0,0.15)",
1675
+ zIndex: 9999998,
1676
+ transition: "right 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
1677
+ overflowY: "auto",
1678
+ padding: "0",
1679
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
1680
+ color: COLORS.text,
1681
+ textAlign: "left"
1682
+ },
1683
+ header: {
1684
+ padding: "24px",
1685
+ background: COLORS.primary,
1686
+ color: "white",
1687
+ position: "sticky",
1688
+ top: 0,
1689
+ zIndex: 10
1690
+ },
1691
+ headerTitle: { fontSize: "20px", fontWeight: "bold", margin: "0 0 4px 0", display: "flex", alignItems: "center", gap: "8px" },
1692
+ headerSubtitle: { fontSize: "13px", opacity: 0.8 },
1693
+ content: { padding: "24px" },
1694
+ scoreContainer: { textAlign: "center", marginBottom: "24px" },
1695
+ scoreText: {
1696
+ fontSize: "56px",
1697
+ fontWeight: "bold",
1698
+ color: score > 80 ? COLORS.success : score > 50 ? "#f4b400" : COLORS.warning,
1699
+ lineHeight: "1"
1700
+ },
1701
+ section: { marginTop: "24px", borderTop: `1px solid ${COLORS.border}`, paddingTop: "20px" },
1702
+ sectionTitle: { fontSize: "13px", fontWeight: "bold", textTransform: "uppercase", color: COLORS.muted, marginBottom: "12px", letterSpacing: "0.05em" },
1703
+ googlePreview: { background: "white", padding: "16px", border: `1px solid ${COLORS.border}`, borderRadius: "12px", boxShadow: "0 2px 6px rgba(0,0,0,0.05)" },
1704
+ googleTitle: { color: "#1a0dab", fontSize: "20px", marginBottom: "4px", textDecoration: "none", display: "block", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
1705
+ googleUrl: { color: "#202124", fontSize: "14px", marginBottom: "4px", display: "block" },
1706
+ googleDesc: { color: "#4d5156", fontSize: "14px", lineHeight: "1.58" },
1707
+ socialPreview: { background: "white", border: `1px solid ${COLORS.border}`, borderRadius: "12px", overflow: "hidden", boxShadow: "0 2px 6px rgba(0,0,0,0.05)" },
1708
+ socialImage: { width: "100%", aspectRatio: "1.91/1", background: "#f5f5f5", display: "flex", alignItems: "center", justifyContent: "center", overflow: "hidden" },
1709
+ socialContent: { padding: "12px", background: "#f0f2f5", borderTop: `1px solid ${COLORS.border}` },
1710
+ issue: { background: "#fff1f0", padding: "10px 14px", borderRadius: "6px", marginBottom: "10px", fontSize: "13px", color: "#cf1322", border: "1px solid #ffa39e", display: "flex", alignItems: "flex-start", gap: "8px" },
1711
+ successItem: { background: "#f6ffed", padding: "10px 14px", borderRadius: "6px", marginBottom: "10px", fontSize: "13px", color: "#389e0d", border: "1px solid #b7eb8f", display: "flex", alignItems: "flex-start", gap: "8px" },
1712
+ footer: { marginTop: "32px", padding: "16px", background: "#f8f9fa", borderRadius: "12px", fontSize: "12px", color: COLORS.muted, border: `1px solid ${COLORS.border}` }
1713
+ };
1714
+ return /* @__PURE__ */ jsxs3(Fragment2, { children: [
1715
+ /* @__PURE__ */ jsx18(
1716
+ "button",
1717
+ {
1718
+ style: styles.button,
1719
+ onClick: () => setIsOpen(!isOpen),
1720
+ title: isOpen ? "Close Auditor" : "Open SEO Auditor",
1721
+ children: isOpen ? "\u2715" : "\u{1F50D}"
1722
+ }
1723
+ ),
1724
+ /* @__PURE__ */ jsxs3("div", { style: styles.sidebar, children: [
1725
+ /* @__PURE__ */ jsxs3("div", { style: styles.header, children: [
1726
+ /* @__PURE__ */ jsxs3("div", { style: styles.headerTitle, children: [
1727
+ /* @__PURE__ */ jsx18("span", { children: "\u{1F4CA}" }),
1728
+ " SEO Auditor"
1729
+ ] }),
1730
+ /* @__PURE__ */ jsx18("div", { style: styles.headerSubtitle, children: "Real-time analysis & preview" })
1731
+ ] }),
1732
+ /* @__PURE__ */ jsxs3("div", { style: styles.content, children: [
1733
+ /* @__PURE__ */ jsxs3("div", { style: styles.scoreContainer, children: [
1734
+ /* @__PURE__ */ jsxs3("div", { style: styles.scoreText, children: [
1735
+ score,
1736
+ "%"
1737
+ ] }),
1738
+ /* @__PURE__ */ jsx18("div", { style: { color: COLORS.muted, fontSize: "14px", marginTop: "4px" }, children: "Page SEO Score" })
1739
+ ] }),
1740
+ /* @__PURE__ */ jsxs3("div", { style: styles.section, children: [
1741
+ /* @__PURE__ */ jsx18("div", { style: styles.sectionTitle, children: "Google Search Result" }),
1742
+ /* @__PURE__ */ jsxs3("div", { style: styles.googlePreview, children: [
1743
+ /* @__PURE__ */ jsx18("div", { style: styles.googleTitle, children: data.title || "Add Page Title" }),
1744
+ /* @__PURE__ */ jsx18("div", { style: styles.googleUrl, children: typeof window !== "undefined" ? data.canonical || window.location.href : "" }),
1745
+ /* @__PURE__ */ jsx18("div", { style: styles.googleDesc, children: data.description || "\u26A0\uFE0F Pro Tip: Add a meta description between 120-160 characters to improve search standing." })
1746
+ ] })
1747
+ ] }),
1748
+ /* @__PURE__ */ jsxs3("div", { style: styles.section, children: [
1749
+ /* @__PURE__ */ jsx18("div", { style: styles.sectionTitle, children: "Social Media Preview" }),
1750
+ /* @__PURE__ */ jsxs3("div", { style: styles.socialPreview, children: [
1751
+ /* @__PURE__ */ jsx18("div", { style: styles.socialImage, children: data.ogImage ? /* @__PURE__ */ jsx18("img", { src: data.ogImage, alt: "Social preview", style: { width: "100%", height: "100%", objectFit: "cover" } }) : /* @__PURE__ */ jsx18("div", { style: { color: COLORS.muted, textAlign: "center", padding: "20px" }, children: "\u{1F4F7} No OG image found" }) }),
1752
+ /* @__PURE__ */ jsxs3("div", { style: styles.socialContent, children: [
1753
+ /* @__PURE__ */ jsx18("div", { style: { color: COLORS.muted, fontSize: "11px", textTransform: "uppercase", marginBottom: "2px" }, children: typeof window !== "undefined" ? window.location.hostname : "" }),
1754
+ /* @__PURE__ */ jsx18("div", { style: { fontWeight: "bold", fontSize: "15px", color: COLORS.text, marginBottom: "4px", overflow: "hidden", textOverflow: "ellipsis", display: "-webkit-box", WebkitLineClamp: "2", WebkitBoxOrient: "vertical" }, children: data.ogTitle || data.title || "No Social Title" }),
1755
+ /* @__PURE__ */ jsx18("div", { style: { fontSize: "13px", color: COLORS.muted, overflow: "hidden", textOverflow: "ellipsis", display: "-webkit-box", WebkitLineClamp: "2", WebkitBoxOrient: "vertical" }, children: data.ogDescription || data.description || "No summary available." })
1756
+ ] })
1757
+ ] })
1758
+ ] }),
1759
+ /* @__PURE__ */ jsxs3("div", { style: styles.section, children: [
1760
+ /* @__PURE__ */ jsx18("div", { style: styles.sectionTitle, children: "SEO Audit Checklist" }),
1761
+ issues.length > 0 ? issues.map((issue, i) => /* @__PURE__ */ jsxs3("div", { style: styles.issue, children: [
1762
+ /* @__PURE__ */ jsx18("span", { style: { fontWeight: "bold" }, children: "\u274C" }),
1763
+ /* @__PURE__ */ jsx18("span", { children: issue })
1764
+ ] }, i)) : /* @__PURE__ */ jsxs3("div", { style: styles.successItem, children: [
1765
+ /* @__PURE__ */ jsx18("span", { style: { fontWeight: "bold" }, children: "\u2705" }),
1766
+ /* @__PURE__ */ jsx18("span", { children: "All structural checks passed! Excellent work." })
1767
+ ] }),
1768
+ data.h1Count === 1 && /* @__PURE__ */ jsxs3("div", { style: styles.successItem, children: [
1769
+ /* @__PURE__ */ jsx18("span", { children: "\u2705" }),
1770
+ " Found exactly one H1 tag"
1771
+ ] }),
1772
+ data.imgWithoutAlt === 0 && /* @__PURE__ */ jsxs3("div", { style: styles.successItem, children: [
1773
+ /* @__PURE__ */ jsx18("span", { children: "\u2705" }),
1774
+ " All images have alt attributes"
1775
+ ] }),
1776
+ data.canonical && /* @__PURE__ */ jsxs3("div", { style: styles.successItem, children: [
1777
+ /* @__PURE__ */ jsx18("span", { children: "\u2705" }),
1778
+ " Canonical link is defined"
1779
+ ] })
1780
+ ] }),
1781
+ /* @__PURE__ */ jsxs3("div", { style: styles.footer, children: [
1782
+ /* @__PURE__ */ jsx18("strong", { children: "\u{1F4A1} Pro Tip:" }),
1783
+ " Use ",
1784
+ /* @__PURE__ */ jsx18("code", { children: "generateArticleMetadata()" }),
1785
+ " or ",
1786
+ /* @__PURE__ */ jsx18("code", { children: "generateProductMetadata()" }),
1787
+ " from ",
1788
+ /* @__PURE__ */ jsx18("code", { children: "@masters-ws/react-seo/core" }),
1789
+ " for one-call professional SEO setup in Next.js."
1790
+ ] })
1791
+ ] })
1792
+ ] })
1793
+ ] });
1794
+ };
1584
1795
  export {
1585
1796
  Breadcrumb,
1586
1797
  JsonLd,
1587
1798
  SEO,
1799
+ SEOAuditor,
1588
1800
  SEOProvider,
1589
1801
  SeoArticle,
1590
1802
  SeoAuthor,
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@masters-ws/react-seo",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "description": "Professional high-performance SEO package for React/Next.js. Zero-dependency core for Next.js App Router, optional Helmet components for React.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
- "require": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.mjs",
12
- "types": "./dist/index.d.ts"
12
+ "require": "./dist/index.js"
13
13
  },
14
14
  "./core": {
15
- "require": "./dist/core/index.js",
15
+ "types": "./dist/core/index.d.ts",
16
16
  "import": "./dist/core/index.mjs",
17
- "types": "./dist/core/index.d.ts"
17
+ "require": "./dist/core/index.js"
18
18
  }
19
19
  },
20
20
  "files": [