@veluai/velu 0.2.18 → 0.2.19
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 +64 -64
- package/runtime/velu-ui/index.js +1 -0
- package/runtime/velu-ui/lib/page-feedback.js +72 -0
- package/src/runtime/App.jsx +24 -1
package/package.json
CHANGED
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@veluai/velu",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"type": "module",
|
|
5
|
-
"bin": "./dist/cli.js",
|
|
6
|
-
"publishConfig": {
|
|
7
|
-
"access": "public"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"dist/**",
|
|
11
|
-
"src/runtime/**",
|
|
12
|
-
"src/navigation.js",
|
|
13
|
-
"src/template.html",
|
|
14
|
-
"src/lib/issues.js",
|
|
15
|
-
"src/lib/extract-mdx-error.js",
|
|
16
|
-
"src/lib/known-components.js",
|
|
17
|
-
"runtime/velu-ui/**",
|
|
18
|
-
"schema/**",
|
|
19
|
-
"templates/**"
|
|
20
|
-
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "node scripts/build.mjs",
|
|
23
|
-
"prepack": "node scripts/build.mjs",
|
|
24
|
-
"build:preview-runtime": "vite build -c vite.preview.config.mjs",
|
|
25
|
-
"test:parity": "node scripts/parity-test.mjs"
|
|
26
|
-
},
|
|
27
|
-
"dependencies": {
|
|
28
|
-
"@apidevtools/swagger-parser": "^10.1.0",
|
|
29
|
-
"@icons-pack/react-simple-icons": ">=13.0.0 <13.13.0",
|
|
30
|
-
"@mdx-js/mdx": "^3.1.1",
|
|
31
|
-
"@mdx-js/react": "^3.1.1",
|
|
32
|
-
"@mdx-js/rollup": "^3.1.1",
|
|
33
|
-
"@tailwindcss/vite": "^4.1.0",
|
|
34
|
-
"@vitejs/plugin-react": "^4.3.4",
|
|
35
|
-
"chokidar": "^3.6.0",
|
|
36
|
-
"estree-util-value-to-estree": "^3.5.0",
|
|
37
|
-
"express": "^4.21.1",
|
|
38
|
-
"github-slugger": "^2.0.0",
|
|
39
|
-
"iso-639-1": "^3.1.5",
|
|
40
|
-
"js-yaml": "^4.1.0",
|
|
41
|
-
"lucide-react": "^0.460.0",
|
|
42
|
-
"mdast-util-to-string": "^4.0.0",
|
|
43
|
-
"prism-react-renderer": "^2.4.0",
|
|
44
|
-
"prismjs": "^1.29.0",
|
|
45
|
-
"react": "^18.3.1",
|
|
46
|
-
"react-dom": "^18.3.1",
|
|
47
|
-
"react-router-dom": "^6.28.0",
|
|
48
|
-
"rehype-slug": "^6.0.0",
|
|
49
|
-
"remark-frontmatter": "^5.0.0",
|
|
50
|
-
"remark-gfm": "^4.0.1",
|
|
51
|
-
"remark-mdx-frontmatter": "^5.2.0",
|
|
52
|
-
"tailwindcss": "^4.1.0",
|
|
53
|
-
"unist-util-visit": "^5.1.0",
|
|
54
|
-
"vite": "^5.4.11"
|
|
55
|
-
},
|
|
56
|
-
"devDependencies": {
|
|
57
|
-
"@fontsource/outfit": "^5.0.0",
|
|
58
|
-
"@resvg/resvg-js": "^2.6.2",
|
|
59
|
-
"esbuild": "^0.28.0",
|
|
60
|
-
"pagefind": "^1.3.0",
|
|
61
|
-
"playwright": "^1.48.0",
|
|
62
|
-
"satori": "^0.12.0"
|
|
63
|
-
}
|
|
64
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@veluai/velu",
|
|
3
|
+
"version": "0.2.19",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": "./dist/cli.js",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/**",
|
|
11
|
+
"src/runtime/**",
|
|
12
|
+
"src/navigation.js",
|
|
13
|
+
"src/template.html",
|
|
14
|
+
"src/lib/issues.js",
|
|
15
|
+
"src/lib/extract-mdx-error.js",
|
|
16
|
+
"src/lib/known-components.js",
|
|
17
|
+
"runtime/velu-ui/**",
|
|
18
|
+
"schema/**",
|
|
19
|
+
"templates/**"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "node scripts/build.mjs",
|
|
23
|
+
"prepack": "node scripts/build.mjs",
|
|
24
|
+
"build:preview-runtime": "vite build -c vite.preview.config.mjs",
|
|
25
|
+
"test:parity": "node scripts/parity-test.mjs"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@apidevtools/swagger-parser": "^10.1.0",
|
|
29
|
+
"@icons-pack/react-simple-icons": ">=13.0.0 <13.13.0",
|
|
30
|
+
"@mdx-js/mdx": "^3.1.1",
|
|
31
|
+
"@mdx-js/react": "^3.1.1",
|
|
32
|
+
"@mdx-js/rollup": "^3.1.1",
|
|
33
|
+
"@tailwindcss/vite": "^4.1.0",
|
|
34
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
35
|
+
"chokidar": "^3.6.0",
|
|
36
|
+
"estree-util-value-to-estree": "^3.5.0",
|
|
37
|
+
"express": "^4.21.1",
|
|
38
|
+
"github-slugger": "^2.0.0",
|
|
39
|
+
"iso-639-1": "^3.1.5",
|
|
40
|
+
"js-yaml": "^4.1.0",
|
|
41
|
+
"lucide-react": "^0.460.0",
|
|
42
|
+
"mdast-util-to-string": "^4.0.0",
|
|
43
|
+
"prism-react-renderer": "^2.4.0",
|
|
44
|
+
"prismjs": "^1.29.0",
|
|
45
|
+
"react": "^18.3.1",
|
|
46
|
+
"react-dom": "^18.3.1",
|
|
47
|
+
"react-router-dom": "^6.28.0",
|
|
48
|
+
"rehype-slug": "^6.0.0",
|
|
49
|
+
"remark-frontmatter": "^5.0.0",
|
|
50
|
+
"remark-gfm": "^4.0.1",
|
|
51
|
+
"remark-mdx-frontmatter": "^5.2.0",
|
|
52
|
+
"tailwindcss": "^4.1.0",
|
|
53
|
+
"unist-util-visit": "^5.1.0",
|
|
54
|
+
"vite": "^5.4.11"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@fontsource/outfit": "^5.0.0",
|
|
58
|
+
"@resvg/resvg-js": "^2.6.2",
|
|
59
|
+
"esbuild": "^0.28.0",
|
|
60
|
+
"pagefind": "^1.3.0",
|
|
61
|
+
"playwright": "^1.48.0",
|
|
62
|
+
"satori": "^0.12.0"
|
|
63
|
+
}
|
|
64
|
+
}
|
package/runtime/velu-ui/index.js
CHANGED
|
@@ -45,6 +45,7 @@ export {
|
|
|
45
45
|
export { default as Search } from './components/Search.jsx';
|
|
46
46
|
export { default as pagefindSearch } from './lib/pagefind.js';
|
|
47
47
|
export { createDocsAssistant } from './lib/docs-assistant.js';
|
|
48
|
+
export { createPageFeedback } from './lib/page-feedback.js';
|
|
48
49
|
export { default as Image } from './components/Image.jsx';
|
|
49
50
|
export {
|
|
50
51
|
default as CodeBlock,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* page-feedback — runtime client for the "Was this page helpful?" widget on a
|
|
3
|
+
* published docs site. POSTs to the backend's PUBLIC feedback API:
|
|
4
|
+
*
|
|
5
|
+
* POST /api/v1/public/feedback ({ page_url, helpful, reason_text, details })
|
|
6
|
+
*
|
|
7
|
+
* Same contract as docs-assistant: the tenant is resolved from the
|
|
8
|
+
* `X-Velu-Site-Host` header (falls back to Origin), and the httponly visitor
|
|
9
|
+
* cookie rides along via `credentials: 'include'` (so the API must be same-site
|
|
10
|
+
* with the docs — true for *.getvelu.com subdomains).
|
|
11
|
+
*
|
|
12
|
+
* `createPageFeedback({ apiBase, host })` returns `{ submit }`, shaped to wire
|
|
13
|
+
* straight into <PageFeedback onVote onSubmit>. Returns null without an apiBase
|
|
14
|
+
* (dev preview / unconfigured site) so the widget stays purely visual.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const trimSlash = (s) => String(s || '').replace(/\/+$/, '');
|
|
18
|
+
|
|
19
|
+
function siteHost(explicit) {
|
|
20
|
+
if (explicit) return explicit;
|
|
21
|
+
return typeof window !== 'undefined' ? window.location.host : '';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// The page the feedback is about. Drop hash + query here; the backend
|
|
25
|
+
// normalizes again server-side so per-page aggregation stays clean.
|
|
26
|
+
function currentPageUrl() {
|
|
27
|
+
if (typeof window === 'undefined') return '';
|
|
28
|
+
const { origin, pathname } = window.location;
|
|
29
|
+
return origin + pathname;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function createPageFeedback({ apiBase, host } = {}) {
|
|
33
|
+
const base = trimSlash(apiBase);
|
|
34
|
+
if (!base) return null;
|
|
35
|
+
const url = `${base}/api/v1/public/feedback`;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Send one feedback submission.
|
|
39
|
+
* - helpful: boolean (Yes / No)
|
|
40
|
+
* - reason: short label from the "No" form (optional)
|
|
41
|
+
* - detail: free-text elaboration (optional)
|
|
42
|
+
* Best-effort: a failed request never disrupts the reader.
|
|
43
|
+
*/
|
|
44
|
+
async function submit({ helpful, reason, detail } = {}) {
|
|
45
|
+
const body = {
|
|
46
|
+
page_url: currentPageUrl(),
|
|
47
|
+
helpful: !!helpful,
|
|
48
|
+
// reason_text is required by the API (min length 1); fall back to a
|
|
49
|
+
// sensible default when the reader didn't pick a reason (e.g. on "Yes").
|
|
50
|
+
reason_text:
|
|
51
|
+
(reason && String(reason).trim()) || (helpful ? 'Helpful' : 'Not helpful'),
|
|
52
|
+
details: detail ? String(detail) : null,
|
|
53
|
+
};
|
|
54
|
+
try {
|
|
55
|
+
await fetch(url, {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
credentials: 'include',
|
|
58
|
+
headers: {
|
|
59
|
+
'Content-Type': 'application/json',
|
|
60
|
+
'X-Velu-Site-Host': siteHost(host),
|
|
61
|
+
},
|
|
62
|
+
body: JSON.stringify(body),
|
|
63
|
+
});
|
|
64
|
+
} catch {
|
|
65
|
+
/* feedback is best-effort — swallow network errors */
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { submit };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export default createPageFeedback;
|
package/src/runtime/App.jsx
CHANGED
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
Search,
|
|
42
42
|
pagefindSearch,
|
|
43
43
|
createDocsAssistant,
|
|
44
|
+
createPageFeedback,
|
|
44
45
|
Logo,
|
|
45
46
|
SocialLinks,
|
|
46
47
|
Tree,
|
|
@@ -779,6 +780,17 @@ function DocsPage() {
|
|
|
779
780
|
return createDocsAssistant({ apiBase, host: site.assistant?.host });
|
|
780
781
|
}, []);
|
|
781
782
|
|
|
783
|
+
// Page-feedback backend: reuses the same injected apiBase as the assistant
|
|
784
|
+
// (baked into every published velu.json), so the "Was this page helpful?"
|
|
785
|
+
// widget can POST to /api/v1/public/feedback. Null in the dev preview, where
|
|
786
|
+
// the widget stays purely visual.
|
|
787
|
+
const pageFeedback = React.useMemo(() => {
|
|
788
|
+
if (IS_DEV_PREVIEW) return null;
|
|
789
|
+
const apiBase = site.assistant?.apiBase;
|
|
790
|
+
if (!apiBase) return null;
|
|
791
|
+
return createPageFeedback({ apiBase, host: site.assistant?.host });
|
|
792
|
+
}, []);
|
|
793
|
+
|
|
782
794
|
const frontmatter = entry?.frontmatter ?? {};
|
|
783
795
|
const PageComponent = entry?.Component ?? null;
|
|
784
796
|
const pageToc = entry?.toc ?? [];
|
|
@@ -1572,7 +1584,18 @@ function DocsPage() {
|
|
|
1572
1584
|
{/* Page-foot feedback widget — ref'd so the sticky AskBar
|
|
1573
1585
|
above can hide as the user scrolls near it. */}
|
|
1574
1586
|
<div ref={feedbackRef} style={{ marginTop: 'var(--s3)' }}>
|
|
1575
|
-
|
|
1587
|
+
{/* key resets the widget's vote state on page change. "Yes"
|
|
1588
|
+
submits immediately; "No" submits once its form is sent.
|
|
1589
|
+
Handlers are no-ops in the dev preview (pageFeedback null). */}
|
|
1590
|
+
<PageFeedback
|
|
1591
|
+
key={pathname}
|
|
1592
|
+
onVote={(v) => {
|
|
1593
|
+
if (v === 'yes') pageFeedback?.submit({ helpful: true });
|
|
1594
|
+
}}
|
|
1595
|
+
onSubmit={({ reason, detail }) =>
|
|
1596
|
+
pageFeedback?.submit({ helpful: false, reason, detail })
|
|
1597
|
+
}
|
|
1598
|
+
/>
|
|
1576
1599
|
</div>
|
|
1577
1600
|
{/* Previous / next page navigation — derived from the
|
|
1578
1601
|
sidebar reading order of the active section. */}
|