@seoengine.ai/next-llm-ready 1.0.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 ADDED
@@ -0,0 +1,858 @@
1
+ # @seoengine.ai/next-llm-ready
2
+
3
+ <p align="center">
4
+ <img src="https://img.shields.io/npm/v/@seoengine.ai/next-llm-ready.svg" alt="npm version" />
5
+ <img src="https://img.shields.io/npm/dm/@seoengine.ai/next-llm-ready.svg" alt="npm downloads" />
6
+ <img src="https://img.shields.io/github/license/SEOengineai/next-llm-ready.svg" alt="license" />
7
+ <img src="https://img.shields.io/badge/TypeScript-Ready-blue.svg" alt="TypeScript" />
8
+ <img src="https://img.shields.io/badge/Next.js-13%2B-black.svg" alt="Next.js" />
9
+ </p>
10
+
11
+ <p align="center">
12
+ <strong>Make your Next.js content AI-ready in seconds.</strong><br>
13
+ Copy buttons, Table of Contents, `/llms.txt` endpoint, and `?llm=1` query support.
14
+ </p>
15
+
16
+ ---
17
+
18
+ ## Why next-llm-ready?
19
+
20
+ Large Language Models (LLMs) like ChatGPT, Claude, and Gemini are increasingly used to consume web content. **next-llm-ready** makes your Next.js content instantly accessible to AI assistants by:
21
+
22
+ - **One-click copy** - Users can copy your content as clean Markdown
23
+ - **LLM-optimized endpoints** - `/llms.txt` and `?llm=1` for AI crawlers
24
+ - **Table of Contents** - Auto-generated navigation with active heading tracking
25
+ - **Analytics** - Track how users interact with your AI-ready content
26
+ - **Zero config** - Works out of the box with sensible defaults
27
+
28
+ ## Quick Start
29
+
30
+ ### Installation
31
+
32
+ ```bash
33
+ npm install @seoengine.ai/next-llm-ready
34
+ # or
35
+ yarn add @seoengine.ai/next-llm-ready
36
+ # or
37
+ pnpm add @seoengine.ai/next-llm-ready
38
+ ```
39
+
40
+ ### Import Styles
41
+
42
+ ```tsx
43
+ // app/layout.tsx or _app.tsx
44
+ import '@seoengine.ai/next-llm-ready/styles.css';
45
+ ```
46
+
47
+ ### Add Copy Button
48
+
49
+ ```tsx
50
+ import { CopyButton } from '@seoengine.ai/next-llm-ready';
51
+
52
+ export default function Article({ title, content, url }) {
53
+ return (
54
+ <article>
55
+ <CopyButton
56
+ content={{ title, content, url }}
57
+ text="Copy for AI"
58
+ />
59
+ <h1>{title}</h1>
60
+ <div dangerouslySetInnerHTML={{ __html: content }} />
61
+ </article>
62
+ );
63
+ }
64
+ ```
65
+
66
+ **That's it!** Your content is now AI-ready.
67
+
68
+ ---
69
+
70
+ ## Features
71
+
72
+ | Feature | Description |
73
+ |---------|-------------|
74
+ | [CopyButton](#copybutton) | Simple copy button with success feedback |
75
+ | [CopyDropdown](#copydropdown) | Split button with copy/view/download menu |
76
+ | [TOC](#toc) | Sticky table of contents with active tracking |
77
+ | [LLMBadge](#llmbadge) | Visual indicator that content is AI-ready |
78
+ | [useLLMCopy](#usellmcopy) | Hook for custom copy implementations |
79
+ | [useTOC](#usetoc) | Hook for custom TOC implementations |
80
+ | [/llms.txt](#llmstxt-endpoint) | Sitemap-like file for AI crawlers |
81
+ | [?llm=1](#llm1-query-parameter) | Markdown version of any page |
82
+ | [Analytics](#analytics) | Track copy events and engagement |
83
+
84
+ ---
85
+
86
+ ## Components
87
+
88
+ ### CopyButton
89
+
90
+ Simple button that copies content as Markdown to clipboard.
91
+
92
+ ```tsx
93
+ import { CopyButton } from '@seoengine.ai/next-llm-ready';
94
+
95
+ <CopyButton
96
+ content={{
97
+ title: "Getting Started with Next.js",
98
+ content: "<p>Next.js is a React framework...</p>",
99
+ url: "https://example.com/nextjs-guide",
100
+ author: "John Doe",
101
+ publishedAt: "2024-01-15",
102
+ tags: ["nextjs", "react", "tutorial"]
103
+ }}
104
+ text="Copy for AI"
105
+ toastMessage="Copied!"
106
+ position="inline" // 'inline' | 'fixed' | 'sticky'
107
+ keyboardShortcut={true} // Ctrl/Cmd + Shift + C
108
+ />
109
+ ```
110
+
111
+ #### Props
112
+
113
+ | Prop | Type | Default | Description |
114
+ |------|------|---------|-------------|
115
+ | `content` | `LLMContent` | required | Content to copy |
116
+ | `text` | `string` | `'Copy'` | Button text |
117
+ | `position` | `'inline' \| 'fixed' \| 'sticky'` | `'inline'` | Button positioning |
118
+ | `keyboardShortcut` | `boolean` | `true` | Enable Ctrl/Cmd+Shift+C |
119
+ | `toastMessage` | `string` | `'Copied!'` | Success message |
120
+ | `toastDuration` | `number` | `2000` | Toast display time (ms) |
121
+ | `disabled` | `boolean` | `false` | Disable button |
122
+ | `className` | `string` | `''` | Additional CSS classes |
123
+ | `onCopy` | `(action: CopyAction) => void` | - | Copy callback |
124
+ | `onError` | `(error: Error) => void` | - | Error callback |
125
+ | `onAnalytics` | `(event: AnalyticsEvent) => void` | - | Analytics callback |
126
+
127
+ ### CopyDropdown
128
+
129
+ Split button with dropdown menu for copy, view, and download options.
130
+
131
+ ```tsx
132
+ import { CopyDropdown } from '@seoengine.ai/next-llm-ready';
133
+
134
+ <CopyDropdown
135
+ content={{
136
+ title: "API Documentation",
137
+ content: "<h2>Authentication</h2><p>Use Bearer tokens...</p>",
138
+ url: "https://docs.example.com/api",
139
+ }}
140
+ text="Copy for AI"
141
+ menuItems={[
142
+ { id: 'copy', label: 'Copy to clipboard', action: 'copy', shortcut: '⌘+Shift+C' },
143
+ { id: 'view', label: 'View markdown', action: 'view' },
144
+ { id: 'download', label: 'Download .md file', action: 'download' },
145
+ ]}
146
+ />
147
+ ```
148
+
149
+ #### Props
150
+
151
+ Extends `CopyButtonProps` with:
152
+
153
+ | Prop | Type | Default | Description |
154
+ |------|------|---------|-------------|
155
+ | `menuItems` | `DropdownMenuItem[]` | Default items | Menu options |
156
+
157
+ #### Menu Item
158
+
159
+ ```tsx
160
+ interface DropdownMenuItem {
161
+ id: string;
162
+ label: string;
163
+ action: 'copy' | 'view' | 'download' | (() => void);
164
+ icon?: React.ReactNode;
165
+ shortcut?: string;
166
+ }
167
+ ```
168
+
169
+ ### TOC
170
+
171
+ Sticky table of contents with active heading highlighting.
172
+
173
+ ```tsx
174
+ 'use client';
175
+
176
+ import { useRef } from 'react';
177
+ import { TOC } from '@seoengine.ai/next-llm-ready';
178
+
179
+ export default function Article({ content }) {
180
+ const contentRef = useRef<HTMLDivElement>(null);
181
+
182
+ return (
183
+ <div className="article-layout">
184
+ <TOC
185
+ contentRef={contentRef}
186
+ title="On This Page"
187
+ levels={['h2', 'h3']}
188
+ sticky
189
+ stickyOffset={80}
190
+ position="right"
191
+ highlightActive
192
+ collapsible
193
+ />
194
+ <article ref={contentRef}>
195
+ <h2 id="intro">Introduction</h2>
196
+ <p>Content here...</p>
197
+ <h3 id="setup">Setup</h3>
198
+ <p>More content...</p>
199
+ </article>
200
+ </div>
201
+ );
202
+ }
203
+ ```
204
+
205
+ #### Props
206
+
207
+ | Prop | Type | Default | Description |
208
+ |------|------|---------|-------------|
209
+ | `contentRef` | `RefObject<HTMLElement>` | - | Reference to content container |
210
+ | `headings` | `TOCHeading[]` | - | Manual headings (optional) |
211
+ | `title` | `string` | `'On This Page'` | TOC title |
212
+ | `levels` | `HeadingLevel[]` | `['h2', 'h3', 'h4']` | Heading levels to include |
213
+ | `position` | `'left' \| 'right'` | `'right'` | TOC position |
214
+ | `sticky` | `boolean` | `true` | Enable sticky positioning |
215
+ | `stickyOffset` | `number` | `80` | Top offset when sticky (px) |
216
+ | `smoothScroll` | `boolean` | `true` | Smooth scroll on click |
217
+ | `highlightActive` | `boolean` | `true` | Highlight active heading |
218
+ | `collapsible` | `boolean` | `true` | Allow collapsing |
219
+ | `defaultCollapsed` | `boolean` | `false` | Start collapsed |
220
+
221
+ ### TOCMobile
222
+
223
+ Mobile-optimized TOC with slide-up panel.
224
+
225
+ ```tsx
226
+ import { TOCMobile } from '@seoengine.ai/next-llm-ready';
227
+
228
+ // Same props as TOC
229
+ <TOCMobile contentRef={contentRef} />
230
+ ```
231
+
232
+ ### LLMBadge
233
+
234
+ Visual indicator showing content is AI-ready.
235
+
236
+ ```tsx
237
+ import { LLMBadge } from '@seoengine.ai/next-llm-ready';
238
+
239
+ <LLMBadge
240
+ text="AI Ready"
241
+ size="md" // 'sm' | 'md' | 'lg'
242
+ showTooltip
243
+ tooltipContent="This content is optimized for AI assistants"
244
+ />
245
+ ```
246
+
247
+ ---
248
+
249
+ ## Hooks
250
+
251
+ ### useLLMCopy
252
+
253
+ Core hook for implementing custom copy functionality.
254
+
255
+ ```tsx
256
+ 'use client';
257
+
258
+ import { useLLMCopy } from '@seoengine.ai/next-llm-ready/hooks';
259
+
260
+ function CustomCopyButton({ content }) {
261
+ const { copy, view, download, markdown, isCopying, isSuccess, error } = useLLMCopy({
262
+ content,
263
+ onSuccess: (action) => console.log(`${action} completed`),
264
+ onError: (err) => console.error(err),
265
+ });
266
+
267
+ return (
268
+ <div>
269
+ <button onClick={copy} disabled={isCopying}>
270
+ {isSuccess ? 'Copied!' : 'Copy'}
271
+ </button>
272
+ <button onClick={() => { view(); alert(markdown); }}>View</button>
273
+ <button onClick={download}>Download</button>
274
+ </div>
275
+ );
276
+ }
277
+ ```
278
+
279
+ #### Options
280
+
281
+ | Option | Type | Description |
282
+ |--------|------|-------------|
283
+ | `content` | `LLMContent` | Content to process |
284
+ | `onSuccess` | `(action: CopyAction) => void` | Success callback |
285
+ | `onError` | `(error: Error) => void` | Error callback |
286
+ | `onAnalytics` | `(event: AnalyticsEvent) => void` | Analytics callback |
287
+
288
+ #### Returns
289
+
290
+ | Property | Type | Description |
291
+ |----------|------|-------------|
292
+ | `copy` | `() => Promise<boolean>` | Copy to clipboard |
293
+ | `view` | `() => string` | Get markdown content |
294
+ | `download` | `() => void` | Download as .md file |
295
+ | `markdown` | `string` | Generated markdown |
296
+ | `isCopying` | `boolean` | Copy in progress |
297
+ | `isSuccess` | `boolean` | Copy succeeded |
298
+ | `error` | `Error \| null` | Last error |
299
+
300
+ ### useTOC
301
+
302
+ Hook for building custom table of contents.
303
+
304
+ ```tsx
305
+ 'use client';
306
+
307
+ import { useTOC } from '@seoengine.ai/next-llm-ready/hooks';
308
+
309
+ function CustomTOC({ contentRef }) {
310
+ const { headings, activeId, scrollTo } = useTOC({
311
+ contentRef,
312
+ levels: ['h2', 'h3'],
313
+ });
314
+
315
+ return (
316
+ <nav>
317
+ {headings.map((heading) => (
318
+ <a
319
+ key={heading.id}
320
+ href={`#${heading.id}`}
321
+ onClick={(e) => {
322
+ e.preventDefault();
323
+ scrollTo(heading.id);
324
+ }}
325
+ style={{ fontWeight: activeId === heading.id ? 'bold' : 'normal' }}
326
+ >
327
+ {heading.text}
328
+ </a>
329
+ ))}
330
+ </nav>
331
+ );
332
+ }
333
+ ```
334
+
335
+ #### Options
336
+
337
+ | Option | Type | Description |
338
+ |--------|------|-------------|
339
+ | `contentRef` | `RefObject<HTMLElement>` | Content container |
340
+ | `levels` | `HeadingLevel[]` | Heading levels |
341
+
342
+ #### Returns
343
+
344
+ | Property | Type | Description |
345
+ |----------|------|-------------|
346
+ | `headings` | `TOCHeading[]` | Extracted headings |
347
+ | `activeId` | `string \| null` | Current active heading |
348
+ | `scrollTo` | `(id: string) => void` | Scroll to heading |
349
+
350
+ ### useAnalytics
351
+
352
+ Track user interactions with copy functionality.
353
+
354
+ ```tsx
355
+ 'use client';
356
+
357
+ import { useAnalytics } from '@seoengine.ai/next-llm-ready/hooks';
358
+
359
+ function TrackedComponent() {
360
+ const { track } = useAnalytics({
361
+ endpoint: '/api/analytics',
362
+ contentId: 'article-123',
363
+ });
364
+
365
+ return (
366
+ <button onClick={() => track('copy')}>
367
+ Copy
368
+ </button>
369
+ );
370
+ }
371
+ ```
372
+
373
+ ---
374
+
375
+ ## Server Utilities
376
+
377
+ ### generateMarkdown
378
+
379
+ Convert HTML content to clean Markdown.
380
+
381
+ ```tsx
382
+ import { generateMarkdown } from '@seoengine.ai/next-llm-ready/server';
383
+
384
+ const markdown = generateMarkdown({
385
+ title: 'My Article',
386
+ content: '<p>Hello <strong>world</strong>!</p>',
387
+ url: 'https://example.com/article',
388
+ author: 'John Doe',
389
+ publishedAt: '2024-01-15',
390
+ });
391
+
392
+ // Output:
393
+ // # My Article
394
+ //
395
+ // **Source:** https://example.com/article
396
+ // **Author:** John Doe
397
+ // **Published:** 2024-01-15
398
+ //
399
+ // ---
400
+ //
401
+ // Hello **world**!
402
+ ```
403
+
404
+ ### generateLLMsTxt
405
+
406
+ Generate an llms.txt file for your site.
407
+
408
+ ```tsx
409
+ import { generateLLMsTxt } from '@seoengine.ai/next-llm-ready/server';
410
+
411
+ const llmsTxt = generateLLMsTxt({
412
+ siteName: 'My Documentation',
413
+ description: 'API documentation and guides',
414
+ baseUrl: 'https://docs.example.com',
415
+ pages: [
416
+ {
417
+ title: 'Getting Started',
418
+ url: '/getting-started',
419
+ description: 'Quick start guide',
420
+ },
421
+ {
422
+ title: 'API Reference',
423
+ url: '/api-reference',
424
+ description: 'Complete API documentation',
425
+ },
426
+ ],
427
+ });
428
+ ```
429
+
430
+ ---
431
+
432
+ ## API Handlers
433
+
434
+ ### /llms.txt Endpoint
435
+
436
+ Create an `/llms.txt` endpoint for AI crawlers.
437
+
438
+ #### App Router (Next.js 13+)
439
+
440
+ ```tsx
441
+ // app/llms.txt/route.ts
442
+ import { createLLMsTxtHandler } from '@seoengine.ai/next-llm-ready/api';
443
+ import { getAllPages } from '@/lib/content';
444
+
445
+ export const GET = createLLMsTxtHandler({
446
+ siteName: 'My Documentation',
447
+ description: 'Technical documentation and guides',
448
+ getPages: async () => {
449
+ const pages = await getAllPages();
450
+ return pages.map((page) => ({
451
+ title: page.title,
452
+ url: page.slug,
453
+ description: page.excerpt,
454
+ }));
455
+ },
456
+ });
457
+ ```
458
+
459
+ #### Pages Router
460
+
461
+ ```tsx
462
+ // pages/llms.txt.ts
463
+ import { createLLMsTxtHandler } from '@seoengine.ai/next-llm-ready/api';
464
+ import type { NextApiRequest, NextApiResponse } from 'next';
465
+
466
+ const handler = createLLMsTxtHandler({
467
+ siteName: 'My Site',
468
+ getPages: async () => [
469
+ { title: 'Home', url: '/', description: 'Welcome' },
470
+ ],
471
+ });
472
+
473
+ export default async function llmsTxt(req: NextApiRequest, res: NextApiResponse) {
474
+ const response = await handler(req as any);
475
+ res.setHeader('Content-Type', 'text/plain');
476
+ res.send(await response.text());
477
+ }
478
+ ```
479
+
480
+ ### ?llm=1 Query Parameter
481
+
482
+ Serve Markdown version of any page.
483
+
484
+ #### Middleware Approach
485
+
486
+ ```tsx
487
+ // middleware.ts
488
+ import { NextResponse } from 'next/server';
489
+ import type { NextRequest } from 'next/server';
490
+
491
+ export function middleware(request: NextRequest) {
492
+ if (request.nextUrl.searchParams.get('llm') === '1') {
493
+ // Rewrite to markdown endpoint
494
+ const url = request.nextUrl.clone();
495
+ url.pathname = `/api/markdown${url.pathname}`;
496
+ return NextResponse.rewrite(url);
497
+ }
498
+ }
499
+
500
+ export const config = {
501
+ matcher: ['/blog/:path*', '/docs/:path*'],
502
+ };
503
+ ```
504
+
505
+ #### API Route Handler
506
+
507
+ ```tsx
508
+ // app/api/markdown/[...slug]/route.ts
509
+ import { createMarkdownHandler } from '@seoengine.ai/next-llm-ready/api';
510
+ import { getPageBySlug } from '@/lib/content';
511
+
512
+ export const GET = createMarkdownHandler({
513
+ getContent: async (slug) => {
514
+ const page = await getPageBySlug(slug);
515
+ if (!page) return null;
516
+
517
+ return {
518
+ title: page.title,
519
+ content: page.content,
520
+ url: `https://example.com/${slug}`,
521
+ author: page.author,
522
+ publishedAt: page.publishedAt,
523
+ };
524
+ },
525
+ });
526
+ ```
527
+
528
+ ---
529
+
530
+ ## Analytics
531
+
532
+ Track how users interact with your AI-ready content.
533
+
534
+ ### Client-Side Tracking
535
+
536
+ ```tsx
537
+ 'use client';
538
+
539
+ import { CopyButton } from '@seoengine.ai/next-llm-ready';
540
+
541
+ <CopyButton
542
+ content={content}
543
+ onAnalytics={(event) => {
544
+ // Send to your analytics provider
545
+ gtag('event', 'llm_copy', {
546
+ action: event.action,
547
+ content_id: event.contentId,
548
+ });
549
+ }}
550
+ />
551
+ ```
552
+
553
+ ### Server-Side Analytics API
554
+
555
+ ```tsx
556
+ // app/api/llm-analytics/route.ts
557
+ import { createAnalyticsApiHandler } from '@seoengine.ai/next-llm-ready/api';
558
+
559
+ export const POST = createAnalyticsApiHandler({
560
+ onEvent: async (event) => {
561
+ // Store in database
562
+ await db.analytics.create({
563
+ data: {
564
+ action: event.action,
565
+ contentId: event.contentId,
566
+ timestamp: new Date(),
567
+ },
568
+ });
569
+ },
570
+ });
571
+ ```
572
+
573
+ ---
574
+
575
+ ## Theming
576
+
577
+ All components use CSS custom properties for easy theming.
578
+
579
+ ### Override Variables
580
+
581
+ ```css
582
+ :root {
583
+ /* Primary colors */
584
+ --llm-ready-primary: #0070f3;
585
+ --llm-ready-primary-hover: #0060df;
586
+
587
+ /* Text colors */
588
+ --llm-ready-text: #1f2937;
589
+ --llm-ready-text-muted: #6b7280;
590
+
591
+ /* Backgrounds */
592
+ --llm-ready-bg: #ffffff;
593
+ --llm-ready-bg-secondary: #f9fafb;
594
+
595
+ /* Borders */
596
+ --llm-ready-border: #e5e7eb;
597
+ --llm-ready-radius: 8px;
598
+
599
+ /* Shadows */
600
+ --llm-ready-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
601
+ }
602
+ ```
603
+
604
+ ### Dark Mode
605
+
606
+ Automatic dark mode support via `prefers-color-scheme`, or use the `.dark` class:
607
+
608
+ ```tsx
609
+ <body className={isDark ? 'dark' : ''}>
610
+ <CopyButton content={content} />
611
+ </body>
612
+ ```
613
+
614
+ ### Tailwind CSS Integration
615
+
616
+ ```tsx
617
+ <CopyButton
618
+ content={content}
619
+ className="rounded-lg shadow-lg hover:shadow-xl"
620
+ />
621
+ ```
622
+
623
+ ---
624
+
625
+ ## TypeScript
626
+
627
+ Full TypeScript support with exported types.
628
+
629
+ ```tsx
630
+ import type {
631
+ LLMContent,
632
+ CopyButtonProps,
633
+ TOCHeading,
634
+ AnalyticsEvent,
635
+ } from '@seoengine.ai/next-llm-ready';
636
+
637
+ const content: LLMContent = {
638
+ title: 'My Article',
639
+ content: '<p>Content...</p>',
640
+ url: 'https://example.com/article',
641
+ };
642
+ ```
643
+
644
+ ### Type Definitions
645
+
646
+ ```tsx
647
+ interface LLMContent {
648
+ title: string;
649
+ content: string; // HTML content
650
+ url?: string; // Canonical URL
651
+ author?: string; // Author name
652
+ publishedAt?: string; // ISO date string
653
+ modifiedAt?: string; // ISO date string
654
+ tags?: string[]; // Content tags
655
+ categories?: string[]; // Content categories
656
+ excerpt?: string; // Short description
657
+ metadata?: Record<string, unknown>;
658
+ }
659
+
660
+ interface TOCHeading {
661
+ id: string;
662
+ text: string;
663
+ level: number;
664
+ children?: TOCHeading[];
665
+ }
666
+
667
+ type CopyAction = 'copy' | 'view' | 'download';
668
+
669
+ interface AnalyticsEvent {
670
+ action: CopyAction;
671
+ contentId?: string;
672
+ contentTitle?: string;
673
+ timestamp: number;
674
+ }
675
+ ```
676
+
677
+ ---
678
+
679
+ ## Examples
680
+
681
+ ### Blog Post Page
682
+
683
+ ```tsx
684
+ // app/blog/[slug]/page.tsx
685
+ import { CopyDropdown, TOC, LLMBadge } from '@seoengine.ai/next-llm-ready';
686
+ import { getPost } from '@/lib/posts';
687
+
688
+ export default async function BlogPost({ params }) {
689
+ const post = await getPost(params.slug);
690
+
691
+ return (
692
+ <div className="max-w-6xl mx-auto flex gap-8">
693
+ {/* Sidebar TOC */}
694
+ <aside className="hidden lg:block w-64">
695
+ <TOC
696
+ headings={post.headings}
697
+ sticky
698
+ stickyOffset={100}
699
+ />
700
+ </aside>
701
+
702
+ {/* Main Content */}
703
+ <article className="flex-1">
704
+ <header className="mb-8">
705
+ <div className="flex items-center gap-4 mb-4">
706
+ <LLMBadge />
707
+ <CopyDropdown
708
+ content={{
709
+ title: post.title,
710
+ content: post.content,
711
+ url: `https://example.com/blog/${params.slug}`,
712
+ author: post.author,
713
+ publishedAt: post.publishedAt,
714
+ }}
715
+ text="Copy for AI"
716
+ />
717
+ </div>
718
+ <h1>{post.title}</h1>
719
+ </header>
720
+
721
+ <div dangerouslySetInnerHTML={{ __html: post.content }} />
722
+ </article>
723
+ </div>
724
+ );
725
+ }
726
+ ```
727
+
728
+ ### Documentation Site
729
+
730
+ ```tsx
731
+ // app/docs/[...slug]/page.tsx
732
+ import { CopyButton, TOC, TOCMobile } from '@seoengine.ai/next-llm-ready';
733
+ import { getDoc } from '@/lib/docs';
734
+
735
+ export default async function DocPage({ params }) {
736
+ const doc = await getDoc(params.slug.join('/'));
737
+
738
+ return (
739
+ <>
740
+ {/* Mobile TOC */}
741
+ <TOCMobile headings={doc.headings} />
742
+
743
+ <div className="lg:grid lg:grid-cols-[1fr_250px] gap-8">
744
+ <article>
745
+ <div className="flex items-center justify-between mb-6">
746
+ <h1>{doc.title}</h1>
747
+ <CopyButton
748
+ content={{
749
+ title: doc.title,
750
+ content: doc.content,
751
+ url: `https://docs.example.com/${params.slug.join('/')}`,
752
+ }}
753
+ text="Copy"
754
+ />
755
+ </div>
756
+ <div dangerouslySetInnerHTML={{ __html: doc.content }} />
757
+ </article>
758
+
759
+ {/* Desktop TOC */}
760
+ <aside className="hidden lg:block">
761
+ <TOC headings={doc.headings} sticky />
762
+ </aside>
763
+ </div>
764
+ </>
765
+ );
766
+ }
767
+ ```
768
+
769
+ ### Headless Implementation
770
+
771
+ Build completely custom UI with hooks:
772
+
773
+ ```tsx
774
+ 'use client';
775
+
776
+ import { useLLMCopy, useTOC } from '@seoengine.ai/next-llm-ready/hooks';
777
+ import { motion, AnimatePresence } from 'framer-motion';
778
+
779
+ function CustomCopyButton({ content }) {
780
+ const { copy, isCopying, isSuccess } = useLLMCopy({ content });
781
+
782
+ return (
783
+ <motion.button
784
+ onClick={copy}
785
+ disabled={isCopying}
786
+ animate={{ scale: isSuccess ? [1, 1.1, 1] : 1 }}
787
+ >
788
+ <AnimatePresence mode="wait">
789
+ {isSuccess ? (
790
+ <motion.span key="success" initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
791
+ Copied!
792
+ </motion.span>
793
+ ) : (
794
+ <motion.span key="copy" initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
795
+ Copy for AI
796
+ </motion.span>
797
+ )}
798
+ </AnimatePresence>
799
+ </motion.button>
800
+ );
801
+ }
802
+ ```
803
+
804
+ ---
805
+
806
+ ## Browser Support
807
+
808
+ - Chrome 90+
809
+ - Firefox 88+
810
+ - Safari 14+
811
+ - Edge 90+
812
+
813
+ Uses modern APIs:
814
+ - Clipboard API (with fallback)
815
+ - Intersection Observer
816
+ - CSS Custom Properties
817
+
818
+ ---
819
+
820
+ ## Contributing
821
+
822
+ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
823
+
824
+ ```bash
825
+ # Clone the repository
826
+ git clone https://github.com/SEOengineai/next-llm-ready.git
827
+
828
+ # Install dependencies
829
+ pnpm install
830
+
831
+ # Run development
832
+ pnpm dev
833
+
834
+ # Run tests
835
+ pnpm test
836
+
837
+ # Build
838
+ pnpm build
839
+ ```
840
+
841
+ ---
842
+
843
+ ## License
844
+
845
+ MIT License - see [LICENSE](LICENSE) for details.
846
+
847
+ ---
848
+
849
+ ## Related Projects
850
+
851
+ - [LLM Ready WordPress Plugin](https://wordpress.org/plugins/llm-ready/) - Original WordPress plugin
852
+ - [llms.txt Specification](https://llmstxt.org/) - Standard for AI-readable content
853
+
854
+ ---
855
+
856
+ <p align="center">
857
+ Made with for the AI-first web
858
+ </p>