PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.5
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.5
4.9.5 4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 All 203 releases
betterdocs / react-src / admin / quick-setup / fields / SampleDocsGenerator.js

SampleDocsGenerator.js in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.9.5, at react-src/admin/quick-setup/fields/SampleDocsGenerator.js

149 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import React from "react";
2 import { useState, useEffect } from "@wordpress/element";
3 import { __, sprintf } from "@wordpress/i18n";
4 import { decodeEntities } from "@wordpress/html-entities";
5 import { Sparkle, IconDoc } from "../../sample-docs/icons";
6 import { AiBadge, GenerateBtn, PopulatedDocs } from "../../sample-docs/Pieces";
7 import SampleDocsFlow from "../../sample-docs/SampleDocsFlow";
8 import { sampleDocsEnabled, fetchExistingDocs } from "../../sample-docs/api";
9
10 /* Quick Setup "Create Content" field — replaces the old DocCreate.gif.
11 Leads with the AI promo banner ("Skip the blank page"). If the site
12 already has docs/categories (or sample docs were generated this session),
13 it shows them read-only in the All Docs grid instead of the empty prompt.
14 Renders inside the tab content area only; tab header + left nav untouched. */
15
16 /* Persist the generated docs for the wizard session so leaving the page
17 (Dashboard / All Docs) and returning keeps the populated view. */
18 const LS_GEN_KEY = "betterdocs_setup_generated_docs";
19
20 const slimCats = (cats) =>
21 (cats || []).map((c, i) => ({
22 id: c.id || "sd_" + i,
23 name: decodeEntities(c.name || ""),
24 icon: c.icon || "book",
25 color: c.color || "#00B884",
26 articles: (c.articles || []).map((a) => decodeEntities(typeof a === "string" ? a : a?.title || "")),
27 }));
28
29 const readStoredDocs = () => {
30 try {
31 const s = window.localStorage?.getItem(LS_GEN_KEY);
32 const parsed = s ? JSON.parse(s) : null;
33 return Array.isArray(parsed) && parsed.length ? parsed : null;
34 } catch (e) {
35 return null;
36 }
37 };
38
39 function SampleDocsGenerator(props) {
40 const [flowOpen, setFlowOpen] = useState(false);
41 const [generated, setGenerated] = useState(readStoredDocs);
42 const [existing, setExisting] = useState(null);
43 const aiEnabled = sampleDocsEnabled();
44
45 // Detect content the site already has, so the step reflects reality
46 // instead of always prompting "No categories yet".
47 useEffect(() => {
48 if (generated) return; // a fresh generation takes precedence
49 let alive = true;
50 fetchExistingDocs().then((cats) => {
51 if (alive && cats && cats.length) {
52 setExisting(slimCats(cats));
53 }
54 });
55 return () => {
56 alive = false;
57 };
58 }, []);
59
60 if (!aiEnabled) {
61 return null;
62 }
63
64 // What to display in the grid: a fresh generation wins, else existing content.
65 const docs = generated || existing;
66 const totalDocs = docs ? docs.reduce((n, c) => n + (c.articles?.length || 0), 0) : 0;
67
68 return (
69 <div className={`betterdocs-sd-qs ${props?.classes || ""}`}>
70 {/* AI promo + empty prompt only when there are no docs yet. */}
71 {!docs && (
72 <>
73 {/* AI promo banner — green gradient hero, matches the design. */}
74 <div className="betterdocs-sd-promo betterdocs-sd-fade">
75 <span className="betterdocs-sd-promo-glow" aria-hidden="true" />
76 <span className="betterdocs-sd-promo-icon">
77 <Sparkle size={28} />
78 </span>
79 <div className="betterdocs-sd-promo-body">
80 <div className="betterdocs-sd-promo-head">
81 <h4 className="betterdocs-sd-promo-title">
82 {__("Skip the blank page", "betterdocs")}
83 </h4>
84 <AiBadge />
85 </div>
86 <p className="betterdocs-sd-promo-text">
87 {__("BetterDocs can read your site and generate a tailored starter knowledge base — categories and draft articles — in about a minute.", "betterdocs")}
88 </p>
89 </div>
90 <GenerateBtn onClick={() => setFlowOpen(true)}>
91 {__("Generate Sample Docs", "betterdocs")}
92 </GenerateBtn>
93 </div>
94
95 <div className="betterdocs-sd-manual-divider">
96 <span className="betterdocs-sd-manual-line" />
97 <span className="betterdocs-sd-manual-label">{__("or build it yourself", "betterdocs")}</span>
98 <span className="betterdocs-sd-manual-line" />
99 </div>
100 <div className="betterdocs-sd-manual">
101 <span className="betterdocs-sd-manual-icon">
102 <IconDoc size={24} />
103 </span>
104 <div className="betterdocs-sd-manual-title">{__("No categories yet", "betterdocs")}</div>
105 <div className="betterdocs-sd-manual-text">
106 {__("Add your first category and articles manually from the All Docs screen after setup.", "betterdocs")}
107 </div>
108 </div>
109 </>
110 )}
111
112 {docs && docs.length > 0 && (
113 <div className="betterdocs-sd-qs-result">
114 <div className="betterdocs-sd-qs-result-head">
115 {sprintf(
116 generated
117 ? __("%1$d categories · %2$d docs created", "betterdocs")
118 : __("%1$d categories · %2$d docs", "betterdocs"),
119 docs.length,
120 totalDocs
121 )}
122 </div>
123 {/* Read-only preview — no actions available inside the wizard. */}
124 <PopulatedDocs cats={docs} />
125 </div>
126 )}
127
128 {flowOpen && (
129 <SampleDocsFlow
130 contentType="docs"
131 onClose={() => setFlowOpen(false)}
132 onComplete={(result) => {
133 setFlowOpen(false);
134 if (result?.categories?.length) {
135 const slim = slimCats(result.categories);
136 setGenerated(slim);
137 try {
138 window.localStorage?.setItem(LS_GEN_KEY, JSON.stringify(slim));
139 } catch (e) {}
140 }
141 }}
142 />
143 )}
144 </div>
145 );
146 }
147
148 export default SampleDocsGenerator;
149