Skip to content

Commit 305f49c

Browse files
committed
update compoennt
1 parent 920d5d6 commit 305f49c

File tree

9 files changed

+234
-87
lines changed

9 files changed

+234
-87
lines changed

app/api/llms/route.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,14 @@ This is the official documentation site for WAVS, a next-generation AVS platform
307307
308308
For a complete text version of all documentation pages, use https://docs.wavs.xyz/llms-full.txt
309309
310-
## Searching
311-
Users can search the documentation using the search bar at the top of the site.
310+
## llm resources
311+
312+
For more llm-ingestible docs, visit https://docs.wavs.xyz/resources/llms.md
313+
314+
## Search API
315+
316+
Search using the search API endpoint: curl "https://docs.wavs.xyz/api/search-custom?q=your_query"
317+
- returns JSON results with page titles, URLs, and content snippets.
312318
313319
## Contributions
314320
The documentation is open-source and accepts contributions. See the GitHub repository for contributing guidelines.
@@ -326,4 +332,4 @@ For additional support or questions not covered in the documentation, users can
326332
'Content-Type': 'text/plain',
327333
},
328334
});
329-
}
335+
}

app/api/search-custom/route.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// This endpoint is for programmatic/LLM search. The site search bar uses /api/search.
2+
import { getPages } from '@/app/source';
3+
import { NextRequest, NextResponse } from 'next/server';
4+
5+
export const dynamic = 'force-dynamic';
6+
export const revalidate = 0;
7+
8+
interface SearchResult {
9+
title: string;
10+
url: string;
11+
snippet: string;
12+
score: number;
13+
}
14+
15+
// Simple text search function
16+
function searchPages(pages: any[], query: string): SearchResult[] {
17+
const results: SearchResult[] = [];
18+
const lowerQuery = query.toLowerCase();
19+
20+
for (const page of pages) {
21+
let score = 0;
22+
let snippet = '';
23+
24+
// Search in title
25+
const title = page.data.title;
26+
const lowerTitle = title.toLowerCase();
27+
if (lowerTitle.includes(lowerQuery)) {
28+
score += 10;
29+
snippet = title;
30+
}
31+
32+
// Search in description
33+
const description = (page.data as any).description || '';
34+
const lowerDescription = description.toLowerCase();
35+
if (lowerDescription.includes(lowerQuery)) {
36+
score += 5;
37+
if (!snippet) snippet = description;
38+
}
39+
40+
// Search in structured data content
41+
if (page.data.exports.structuredData?.contents) {
42+
for (const content of page.data.exports.structuredData.contents) {
43+
const contentText = content.content || '';
44+
const lowerContent = contentText.toLowerCase();
45+
if (lowerContent.includes(lowerQuery)) {
46+
score += 3;
47+
if (!snippet) {
48+
// Create a snippet from the matching content
49+
const index = lowerContent.indexOf(lowerQuery);
50+
const start = Math.max(0, index - 50);
51+
const end = Math.min(contentText.length, index + lowerQuery.length + 50);
52+
snippet = (start > 0 ? '...' : '') + contentText.substring(start, end) + (end < contentText.length ? '...' : '');
53+
}
54+
}
55+
}
56+
}
57+
58+
// Search in headings
59+
if (page.data.exports.structuredData?.headings) {
60+
for (const heading of page.data.exports.structuredData.headings) {
61+
const headingText = heading.content || '';
62+
const lowerHeading = headingText.toLowerCase();
63+
if (lowerHeading.includes(lowerQuery)) {
64+
score += 7;
65+
if (!snippet) snippet = headingText;
66+
}
67+
}
68+
}
69+
70+
// Add to results if we found matches
71+
if (score > 0) {
72+
results.push({
73+
title,
74+
url: page.url,
75+
snippet: snippet || title,
76+
score
77+
});
78+
}
79+
}
80+
81+
// Sort by score (highest first) and limit results
82+
return results
83+
.sort((a, b) => b.score - a.score)
84+
.slice(0, 10);
85+
}
86+
87+
export async function GET(request: NextRequest) {
88+
const { searchParams } = new URL(request.url);
89+
const query = searchParams.get('q');
90+
91+
if (!query || query.trim() === '') {
92+
return NextResponse.json([]);
93+
}
94+
95+
const pages = getPages();
96+
const results = searchPages(pages, query.trim());
97+
98+
return NextResponse.json(results);
99+
}

app/api/search-debug/route.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { getPages } from '@/app/source';
2+
import { NextRequest, NextResponse } from 'next/server';
3+
4+
export const dynamic = 'force-dynamic';
5+
export const revalidate = 0;
6+
7+
export async function GET(request: NextRequest) {
8+
const pages = getPages();
9+
10+
// Sample a few pages to see their structure
11+
const samplePages = pages.slice(0, 3).map((page) => ({
12+
title: page.data.title,
13+
url: page.url,
14+
hasStructuredData: !!page.data.exports.structuredData,
15+
structuredDataKeys: page.data.exports.structuredData ? Object.keys(page.data.exports.structuredData) : [],
16+
structuredDataSample: page.data.exports.structuredData ?
17+
Object.fromEntries(
18+
Object.entries(page.data.exports.structuredData).slice(0, 2)
19+
) : null,
20+
description: (page.data as any).description || 'No description',
21+
}));
22+
23+
return NextResponse.json({
24+
totalPages: pages.length,
25+
samplePages,
26+
allPageTitles: pages.map(p => p.data.title),
27+
});
28+
}

app/api/search/route.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// This endpoint is for the Fumadocs UI search bar. For programmatic search, use /api/search-custom.
12
import { getPages } from '@/app/source';
23
import { createSearchAPI } from 'fumadocs-core/search/server';
34

components/open-in-llm.tsx

Lines changed: 80 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useState, useRef, useEffect } from 'react';
44
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/collapsible';
5-
import { ChevronDown, ExternalLink, Copy, FileText, Book } from 'lucide-react';
5+
import { ChevronDown, ExternalLink, Copy, FileText, Book, ScrollText, NotepadTextDashed, NotebookText, Map, WandSparkles, Sparkles } from 'lucide-react';
66
import { usePathname } from 'next/navigation';
77
import { useMediaQuery } from './hooks/use-media-query';
88
import Image from 'next/image';
@@ -110,17 +110,8 @@ export const OpenInLLM = () => {
110110
<button
111111
className="flex items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium text-[hsl(var(--text-secondary))] bg-[hsl(var(--background-secondary))] hover:text-[hsl(var(--text-accent))] hover:bg-[hsl(var(--background-accent))] transition-colors border border-[hsl(var(--border-primary))] shadow-sm"
112112
>
113-
{isMobile ? (
114-
<>
115-
<Book size={18} />
116-
<ChevronDown size={16} className={`transition-transform ${isOpen ? 'rotate-180' : ''}`} />
117-
</>
118-
) : (
119-
<>
120-
<span>Open in LLM</span>
121-
<ChevronDown size={16} className={`transition-transform ${isOpen ? 'rotate-180' : ''}`} />
122-
</>
123-
)}
113+
<Sparkles size={18} />
114+
<ChevronDown size={16} className={`transition-transform ${isOpen ? 'rotate-180' : ''}`} />
124115
</button>
125116
</CollapsibleTrigger>
126117
<CollapsibleContent className="absolute right-0 top-full z-50 mt-1 w-64 rounded-lg bg-[hsl(var(--background-base))] p-1 shadow-lg border border-[hsl(var(--border-primary))]">
@@ -129,7 +120,7 @@ export const OpenInLLM = () => {
129120
href={getClaudeUrl()}
130121
target="_blank"
131122
rel="noopener noreferrer"
132-
className="flex items-center gap-2 px-3 py-2.5 text-sm text-[hsl(var(--text-primary))] hover:bg-[hsl(var(--background-secondary))] no-underline"
123+
className="flex items-center gap-2 px-3 py-2.5 text-sm text-[hsl(var(--text-primary))] hover:bg-[hsl(var(--background-accent))] hover:text-[hsl(var(--text-accent))] no-underline"
133124
onClick={() => setIsOpen(false)}
134125
>
135126
<span className="flex h-5 w-5 items-center justify-center">
@@ -153,7 +144,7 @@ export const OpenInLLM = () => {
153144
href={getChatGPTUrl()}
154145
target="_blank"
155146
rel="noopener noreferrer"
156-
className="flex items-center gap-2 px-3 py-2.5 text-sm text-[hsl(var(--text-primary))] hover:bg-[hsl(var(--background-secondary))] no-underline"
147+
className="flex items-center gap-2 px-3 py-2.5 text-sm text-[hsl(var(--text-primary))] hover:bg-[hsl(var(--background-accent))] hover:text-[hsl(var(--text-accent))] no-underline"
157148
onClick={() => setIsOpen(false)}
158149
>
159150
<span className="flex h-5 w-5 items-center justify-center">
@@ -173,9 +164,15 @@ export const OpenInLLM = () => {
173164
<ExternalLink size={14} className="ml-auto opacity-70" />
174165
</a>
175166

176-
<button
177-
onClick={copyMarkdown}
178-
className="flex w-full items-center gap-2 px-3 py-2.5 text-sm text-[hsl(var(--text-primary))] hover:bg-[hsl(var(--background-secondary))]"
167+
<div className="h-px bg-[hsl(var(--border-primary))] my-1" />
168+
169+
<a
170+
href="#"
171+
onClick={(e) => {
172+
e.preventDefault();
173+
copyMarkdown();
174+
}}
175+
className="flex items-center gap-2 px-3 py-2.5 text-sm text-[hsl(var(--text-primary))] hover:bg-[hsl(var(--background-accent))] hover:text-[hsl(var(--text-accent))] no-underline"
179176
>
180177
<span className="flex h-5 w-5 items-center justify-center">
181178
<Copy size={16} />
@@ -185,13 +182,13 @@ export const OpenInLLM = () => {
185182
<span className="text-xs text-[hsl(var(--text-tertiary))]">Copy page as plaintext</span>
186183
</div>
187184
<ExternalLink size={14} className="ml-auto opacity-0" />
188-
</button>
185+
</a>
189186

190187
<a
191188
href={mounted ? (isIndexPage ? `${window.location.origin}/api/md/docs/index` : markdownUrl) : '#'}
192189
target="_blank"
193190
rel="noopener noreferrer"
194-
className="flex items-center gap-2 px-3 py-2.5 text-sm text-[hsl(var(--text-primary))] hover:bg-[hsl(var(--background-secondary))] no-underline"
191+
className="flex items-center gap-2 px-3 py-2.5 text-sm text-[hsl(var(--text-primary))] hover:bg-[hsl(var(--background-accent))] hover:text-[hsl(var(--text-accent))] no-underline"
195192
onClick={() => setIsOpen(false)}
196193
>
197194
<span className="flex h-5 w-5 items-center justify-center">
@@ -204,26 +201,71 @@ export const OpenInLLM = () => {
204201
<ExternalLink size={14} className="ml-auto opacity-70" />
205202
</a>
206203

207-
<div className="mt-2 px-3 py-2 border-t border-[hsl(var(--border-primary))]">
208-
<div className="grid grid-cols-2 gap-2">
209-
<a
210-
href="/llms.txt"
211-
target="_blank"
212-
rel="noopener noreferrer"
213-
className="flex justify-center items-center gap-1 px-2 py-1.5 text-xs font-medium rounded-md text-[hsl(var(--text-primary))] bg-[hsl(var(--background-secondary))] hover:bg-[hsl(var(--background-primary))] no-underline border border-[hsl(var(--border-primary))] transition-colors"
214-
>
215-
<span>llms.txt</span>
216-
</a>
217-
<a
218-
href="/llms-full.txt"
219-
target="_blank"
220-
rel="noopener noreferrer"
221-
className="flex justify-center items-center gap-1 px-2 py-1.5 text-xs font-medium rounded-md text-[hsl(var(--text-primary))] bg-[hsl(var(--background-secondary))] hover:bg-[hsl(var(--background-primary))] no-underline border border-[hsl(var(--border-primary))] transition-colors"
222-
>
223-
<span>llms-full.txt</span>
224-
</a>
204+
<div className="h-px bg-[hsl(var(--border-primary))] my-1" />
205+
206+
<a
207+
href="/llms.txt"
208+
target="_blank"
209+
rel="noopener noreferrer"
210+
className="flex items-center gap-2 px-3 py-2.5 text-sm text-[hsl(var(--text-primary))] hover:bg-[hsl(var(--background-accent))] hover:text-[hsl(var(--text-accent))] no-underline"
211+
onClick={() => setIsOpen(false)}
212+
>
213+
<span className="flex h-5 w-5 items-center justify-center">
214+
<Map size={16} />
215+
</span>
216+
<div className="flex flex-col">
217+
<span>llms.txt</span>
218+
<span className="text-xs text-[hsl(var(--text-tertiary))]">Docs index for AI</span>
219+
</div>
220+
<ExternalLink size={14} className="ml-auto opacity-70" />
221+
</a>
222+
223+
<a
224+
href="/llms-full.txt"
225+
target="_blank"
226+
rel="noopener noreferrer"
227+
className="flex items-center gap-2 px-3 py-2.5 text-sm text-[hsl(var(--text-primary))] hover:bg-[hsl(var(--background-accent))] hover:text-[hsl(var(--text-accent))] no-underline"
228+
onClick={() => setIsOpen(false)}
229+
>
230+
<span className="flex h-5 w-5 items-center justify-center">
231+
<NotebookText size={16} />
232+
</span>
233+
<div className="flex flex-col">
234+
<span>Full Documentation</span>
235+
<span className="text-xs text-[hsl(var(--text-tertiary))]">Complete docs as text</span>
236+
</div>
237+
<ExternalLink size={14} className="ml-auto opacity-70" />
238+
</a>
239+
240+
<a
241+
href="/resources/llms"
242+
className="flex items-center gap-2 px-3 py-2.5 text-sm text-[hsl(var(--text-primary))] hover:bg-[hsl(var(--background-accent))] hover:text-[hsl(var(--text-accent))] no-underline"
243+
onClick={() => setIsOpen(false)}
244+
>
245+
<span className="flex h-5 w-5 items-center justify-center">
246+
<Book size={16} />
247+
</span>
248+
<div className="flex flex-col">
249+
<span>LLM Resouces</span>
250+
<span className="text-xs text-[hsl(var(--text-tertiary))]">AI-friendly resources</span>
225251
</div>
226-
</div>
252+
<ExternalLink size={14} className="ml-auto opacity-70" />
253+
</a>
254+
255+
<a
256+
href="/handbook/ai"
257+
className="flex items-center gap-2 px-3 py-2.5 text-sm text-[hsl(var(--text-primary))] hover:bg-[hsl(var(--background-accent))] hover:text-[hsl(var(--text-accent))] no-underline"
258+
onClick={() => setIsOpen(false)}
259+
>
260+
<span className="flex h-5 w-5 items-center justify-center">
261+
<WandSparkles size={16} />
262+
</span>
263+
<div className="flex flex-col">
264+
<span>AI template</span>
265+
<span className="text-xs text-[hsl(var(--text-tertiary))]">Create components with AI</span>
266+
</div>
267+
<ExternalLink size={14} className="ml-auto opacity-70" />
268+
</a>
227269
</div>
228270
</CollapsibleContent>
229271
</Collapsible>

content/docs/llm-docs.mdx

Lines changed: 0 additions & 40 deletions
This file was deleted.

content/docs/resources/llms.mdx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@
22
title: LLM docs
33
description: Access WAVS documentation in formats optimized for AI tools and integration.
44
---
5+
import { Callout } from 'fumadocs-ui/components/callout';
6+
import { DocsPage } from 'fumadocs-ui/page';
57

68

9+
<Callout title="AI components" type="info">
10+
To learn how to create one-shot components with AI, visit the [AI-powered component creation page](/handbook/ai)
11+
</Callout>
712

813
The LLM text format presents documentation in a clean, plain text format optimized for large language models (LLMs) like Claude, ChatGPT, and others.
914

@@ -42,3 +47,9 @@ Examples:
4247
- `/overview.md` - Overview page as Markdown
4348
- `/tutorial/1-overview.md` - Tutorial introduction as Markdown
4449
- `/handbook/service.md` - Service handbook as Markdown
50+
51+
## Crate docs
52+
53+
## WAVS foundry template llm docs
54+
55+
An llm-ingestible full markdown version of the [WAVS foundry template](https://github.com/Lay3rLabs/wavs-foundry-template) is available

0 commit comments

Comments
 (0)