Add example

This commit is contained in:
braginini
2026-03-14 17:13:03 +01:00
parent d7d08695fe
commit 45186f6c05
8 changed files with 729 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
+6
View File
@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
transpilePackages: ["@netbirdio/explain"],
};
module.exports = nextConfig;
+520
View File
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
{
"name": "explain-demo",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@netbirdio/explain": "file:..",
"next": "^14.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"typescript": "^5.0.0"
}
}
+19
View File
@@ -0,0 +1,19 @@
import { NextRequest, NextResponse } from "next/server";
/**
* Mock AI endpoint that returns canned responses.
* Replace this with a real createAssistant() handler for production use.
*/
export async function POST(req: NextRequest) {
const { messages } = await req.json();
const last = messages?.[messages.length - 1]?.content ?? "";
// Simulate a short delay
await new Promise((r) => setTimeout(r, 600));
const reply = `This is a demo response to: "${last}"\n\n`
+ `In a real setup you would configure **createAssistant()** from \`@netbirdio/explain/server\` `
+ `with your Anthropic or OpenAI API key to get actual AI responses.`;
return NextResponse.json({ reply });
}
+17
View File
@@ -0,0 +1,17 @@
export const metadata = {
title: "NetBird Explain — Example",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body style={{ margin: 0, background: "#0a0a0f", color: "#f0f0f5" }}>
{children}
</body>
</html>
);
}
+100
View File
@@ -0,0 +1,100 @@
"use client";
import {
AIAssistantProvider,
useAIAssistant,
} from "@netbirdio/explain/client";
function DemoContent() {
const { enterExplainMode, setExplainContext } = useAIAssistant();
return (
<div style={{ maxWidth: 720, margin: "0 auto", padding: "48px 24px", fontFamily: "system-ui, sans-serif" }}>
<h1 style={{ fontSize: 28, marginBottom: 8 }}>NetBird Explain Example</h1>
<p style={{ color: "#9ca3af", marginBottom: 32 }}>
Click the floating button in the bottom-right to open the AI chat, or
use the Explain Mode button below to click on any highlighted element.
</p>
<button
onClick={() => {
setExplainContext({ pageName: "Example Page" });
enterExplainMode();
}}
style={{
padding: "8px 16px",
borderRadius: 8,
border: "1px solid rgba(255,255,255,0.15)",
background: "rgba(255,255,255,0.06)",
color: "#f0f0f5",
cursor: "pointer",
fontSize: 14,
marginBottom: 32,
}}
>
Enter Explain Mode
</button>
{/* Example cards with data-nb-explain annotations */}
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
<Card
title="Peers"
description="Devices connected to your NetBird network."
explain="Peers — devices registered in the NetBird network that can communicate via WireGuard tunnels"
/>
<Card
title="Access Control"
description="Rules that govern which peers can reach each other."
explain="Access Control — firewall-like policies defining allowed traffic between peer groups"
/>
<Card
title="Routes"
description="Network routes distributed to peers for subnet access."
explain="Routes — network routes pushed to peers so they can reach subnets behind a routing peer"
/>
<Card
title="DNS Settings"
description="Custom DNS nameservers and domains for the network."
explain="DNS — custom nameservers and search domains resolved via the NetBird network"
/>
</div>
</div>
);
}
function Card({
title,
description,
explain,
}: {
title: string;
description: string;
explain: string;
}) {
return (
<div
data-nb-explain={explain}
style={{
padding: 20,
borderRadius: 12,
border: "1px solid rgba(255,255,255,0.1)",
background: "rgba(255,255,255,0.04)",
}}
>
<h3 style={{ margin: "0 0 6px", fontSize: 16 }}>{title}</h3>
<p style={{ margin: 0, fontSize: 14, color: "#9ca3af" }}>{description}</p>
</div>
);
}
export default function Page() {
return (
<AIAssistantProvider
endpoint="/api/explain"
title="NetBird AI"
subtitle="Ask about your network"
>
<DemoContent />
</AIAssistantProvider>
);
}
+40
View File
@@ -0,0 +1,40 @@
{
"compilerOptions": {
"target": "ES2020",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./src/*"
]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}