Feedback
Collect feedback on pages and selected text.
Readers rate a page from a form below it, or comment on text they select. You decide where the messages go.
Setup
Install
npm i @fumapress/feedbackAdd the Styles
Add this after the imports in your stylesheet:
@import "@fumapress/feedback/css/preset.css";Choose Where Feedback Goes
Use one of these options. They all register the same routes, so a site can only have one.
Plain functions run on the server, so the site needs a server.
import { feedbackPlugin } from "@fumapress/feedback";
export default createPress(content).plugins(
feedbackPlugin({
async onPageFeedbackAction({ opinion, url, message }) {
await analytics.track("page-feedback", { opinion, url, message });
return {};
},
async onTextFeedbackAction({ url, blockId, blockBody, message }) {
const discussion = await createDiscussion({ url, blockId, blockBody, message });
return { githubUrl: discussion.url };
},
}),
);The returned githubUrl or emailSent tells the form where the feedback went. Types are in @fumapress/feedback/schema.
Rate Limiting
Anyone can post, and the plugins don't limit field lengths or URL schemes. Add rate limiting and bot checks before you go live.
Each plugin takes beforeRequest. Return a Response to reject a request:
feedbackPlugin({
async beforeRequest(req) {
if (await isRateLimited(req)) return new Response("Too Many Requests", { status: 429 });
},
});Custom Layout
The default layout places the form for you.
In a custom layout, place the feedback:page slot in your island:
export const DocsIsland = createIsland(
({ layoutProps, pageData, toc, slots, children }: IslandProps<typeof app, "docs">) => (
<DocsLayout {...layoutProps}>
<DocsPage toc={toc}>
<DocsTitle>{pageData.title}</DocsTitle>
<DocsBody>{children}</DocsBody>
{slots["feedback:page"]?.element}
</DocsPage>
</DocsLayout>
),
);Options
Prop
Type
Last updated on