Skip to content

Documentation uploaded#4

Open
Jils31 wants to merge 1 commit intomainfrom
frontend
Open

Documentation uploaded#4
Jils31 wants to merge 1 commit intomainfrom
frontend

Conversation

@Jils31
Copy link
Copy Markdown
Collaborator

@Jils31 Jils31 commented Oct 31, 2025

Summary by CodeRabbit

  • New Features

    • Interactive documentation viewer with full-text search and navigation sidebar
    • Integrated AI chat assistant for documentation-based Q&A support
  • Documentation

    • Getting started guide covering wallet setup and basic workflow
    • Trading guide with token creation, strategies, and risk management
    • Privacy and security guide with best practices and threat mitigation

@vercel
Copy link
Copy Markdown

vercel bot commented Oct 31, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
nft-maker Error Error Oct 31, 2025 6:26am
solana-token-launchpad Error Error Oct 31, 2025 6:26am

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Oct 31, 2025

Walkthrough

The changes integrate Google Generative AI into a Solana Token Launchpad application. A dependency is added for the Gemini API. Multiple new documentation files are created, UI components are introduced, backend API routes handle documentation serving and chat interactions, and the docs page is refactored to include dynamic content loading with an AI chatbot.

Changes

Cohort / File(s) Summary
Dependencies
package.json
Added "@google/generative-ai" (^0.24.1) for Gemini API integration.
Documentation
public/docs/getting-started.md, public/docs/privacy-security.md, public/docs/trading-guide.md
Three new markdown documentation files covering getting started, privacy & security best practices, and trading strategies for token launchpad.
UI Components
src/app/components/ui/button.tsx, src/app/components/ui/card.tsx, src/app/components/ui/input.tsx
New reusable UI components: Button (with variants), Card family (Card, CardHeader, CardTitle, CardContent), and Input element with styled defaults and responsive properties.
Markdown Renderer
src/app/components/MarkDownRenderer.tsx
New React component rendering markdown with syntax highlighting, copy-to-clipboard for code blocks, table support, heading styles, inline formatting, and external link icons.
Documentation API
src/app/api/docs/[slug]/route.ts
New dynamic GET route serving markdown documentation from public/docs by slug with 404 handling.
Chat API
src/app/api/chat/route.ts
New POST route integrating Gemini AI for chat, loading documentation context, building system prompt, managing conversation history, and returning streamed responses.
Docs Page
src/app/docs/page.tsx
Major refactor from static page to interactive docs viewer with left navigation sidebar, full-text search, dynamic content loading, and integrated AI chatbot with message actions (copy, like/dislike, regenerate).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DocsPage as Docs Page (Client)
    participant DocsAPI as Docs API Route
    participant ChatAPI as Chat API Route
    participant Gemini as Gemini API
    participant FileSystem as File System

    User->>DocsPage: Click doc section
    DocsPage->>DocsAPI: GET /api/docs/{slug}
    DocsAPI->>FileSystem: Read public/docs/{slug}.md
    FileSystem-->>DocsAPI: Markdown content
    DocsAPI-->>DocsPage: { content: "..." }
    DocsPage->>DocsPage: Render via MarkdownRenderer

    User->>DocsPage: Send chat message
    DocsPage->>ChatAPI: POST /api/chat (message, history)
    ChatAPI->>FileSystem: Load all docs
    ChatAPI->>ChatAPI: Build system prompt + context
    ChatAPI->>Gemini: Generate content (prompt + history)
    Gemini-->>ChatAPI: Generated response
    ChatAPI-->>DocsPage: { response: "...", timestamp }
    DocsPage->>DocsPage: Append to chat, show actions (copy, like, regenerate)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Gemini API integration in chat route: Verify proper API key validation, error handling, and rate-limit safeguards. Confirm conversationHistory mapping and system prompt construction.
  • Path traversal security in docs API: Ensure slug parameter cannot escape public/docs directory (no ../ traversal).
  • Chat state management complexity: Review chatState transitions ("collapsed" → "focused" → "expanded"), message list updates, regeneration flow, and edge cases with concurrent requests.
  • MarkdownRenderer security: Verify markdown parsing cannot introduce XSS via user-supplied content or untrusted sources.
  • Environment configuration: Confirm GEMINI_API_KEY handling and fallback behavior in both development and production.

Poem

🐰 A rabbot's delight in documentation

With Gemini's wit and docs all bright,
A chatbot springs to aid in flight,
Markdown dances, cards align,
From Solana tales to trading time—
The warren hops with joy, hooray! 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Documentation uploaded" is partially related to the changeset. While documentation files (getting-started.md, privacy-security.md, trading-guide.md) were indeed added to public/docs, the primary changes involve building an interactive documentation system with multiple supporting components. The main work includes a redesigned interactive docs page (src/app/docs/page.tsx) with sidebar navigation, search functionality, and integrated AI chat powered by Gemini; new API routes for serving documentation and handling chat; and several new UI components (MarkdownRenderer, Button, Card, Input). The title captures only the surface-level addition of documentation files but misses the substantial feature implementation that gives these docs their purpose and functionality.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch frontend

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (2)
src/app/components/ui/card.tsx (1)

23-25: Remove the unnecessary empty string from the className composition.

The empty string "" in the cn() call serves no purpose and can be removed for clarity.

Apply this diff:

 const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
-  ({ className, ...props }, ref) => <div ref={ref} className={cn("", className)} {...props} />,
+  ({ className, ...props }, ref) => <div ref={ref} className={className} {...props} />,
 )
src/app/components/MarkDownRenderer.tsx (1)

1-404: Consider using a well-established markdown library instead of custom parsing.

While the custom implementation is comprehensive, markdown parsing has many edge cases and potential security concerns (like XSS through malformed input). Well-known libraries like react-markdown or remark-react are battle-tested, maintained, and handle edge cases more reliably.

Benefits of using an established library:

  • Reduced maintenance burden
  • Better security (sanitization, XSS prevention)
  • Standard markdown compliance
  • Plugin ecosystem for extensions
  • Performance optimizations

If you need custom styling, most libraries support custom renderers for different elements.

Example with react-markdown:

"use client"

import ReactMarkdown from 'react-markdown'
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'

interface MarkdownRendererProps {
  content: string
}

export function MarkdownRenderer({ content }: MarkdownRendererProps) {
  return (
    <ReactMarkdown
      components={{
        code({ node, inline, className, children, ...props }) {
          const match = /language-(\w+)/.exec(className || '')
          return !inline && match ? (
            <SyntaxHighlighter
              style={vscDarkPlus}
              language={match[1]}
              PreTag="div"
              {...props}
            >
              {String(children).replace(/\n$/, '')}
            </SyntaxHighlighter>
          ) : (
            <code className={className} {...props}>
              {children}
            </code>
          )
        },
        // Add custom styling for other elements
      }}
    >
      {content}
    </ReactMarkdown>
  )
}

Then add to package.json:

"react-markdown": "^9.0.0",
"react-syntax-highlighter": "^15.5.0"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a4b3a46 and 8b64e40.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (11)
  • package.json (1 hunks)
  • public/docs/getting-started.md (1 hunks)
  • public/docs/privacy-security.md (1 hunks)
  • public/docs/trading-guide.md (1 hunks)
  • src/app/api/chat/route.ts (1 hunks)
  • src/app/api/docs/[slug]/route.ts (1 hunks)
  • src/app/components/MarkDownRenderer.tsx (1 hunks)
  • src/app/components/ui/button.tsx (1 hunks)
  • src/app/components/ui/card.tsx (1 hunks)
  • src/app/components/ui/input.tsx (1 hunks)
  • src/app/docs/page.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/app/docs/page.tsx (1)
src/app/components/MarkDownRenderer.tsx (1)
  • MarkdownRenderer (10-404)
🪛 LanguageTool
public/docs/getting-started.md

[style] ~71-~71: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 2171 characters long)
Context: ...? Connect your wallet and begin creating!

(EN_EXCESSIVE_EXCLAMATION)

public/docs/trading-guide.md

[uncategorized] ~16-~16: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...Fast & Cheap* - Benefit from Solana's high speed and low fees ### NFTs (Non-Fungible To...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

public/docs/privacy-security.md

[style] ~364-~364: This phrase is redundant. Consider writing “Consult”.
Context: ...typically required Recommendation: Consult with legal and tax professionals in your jur...

(CONSULT_WITH)

🪛 markdownlint-cli2 (0.18.1)
public/docs/getting-started.md

65-65: No empty links

(MD042, no-empty-links)


66-66: No empty links

(MD042, no-empty-links)


67-67: No empty links

(MD042, no-empty-links)

public/docs/privacy-security.md

399-399: Bare URL used

(MD034, no-bare-urls)


406-406: No empty links

(MD042, no-empty-links)


407-407: No empty links

(MD042, no-empty-links)


408-408: No empty links

(MD042, no-empty-links)


422-422: Bare URL used

(MD034, no-bare-urls)


423-423: Bare URL used

(MD034, no-bare-urls)

🔇 Additional comments (2)
src/app/components/ui/input.tsx (1)

1-25: LGTM!

The Input component follows React best practices with proper forwardRef usage and type-safe props. The implementation is clean and reusable.

package.json (1)

12-12: Version verified: @google/generative-ai@0.24.1 is valid and up-to-date.

The version 0.24.1 exists on npm as the latest release with no known security advisories detected. The caret range (^0.24.1) is appropriate for allowing safe minor and patch updates.

Comment on lines +65 to +67
- Learn about [Token Minting](#) in detail
- Explore [NFT Creation](#) features
- Understand [Best Practices](#) for launching tokens
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Complete the placeholder links or remove them.

These links have empty URLs that should either be filled in with actual destinations or removed if not yet available.

Apply this diff if these sections don't exist yet:

 ## Next Steps
 
-- Learn about [Token Minting](#) in detail
-- Explore [NFT Creation](#) features
-- Understand [Best Practices](#) for launching tokens
+- Learn about Token Minting in detail (guide coming soon)
+- Explore NFT Creation features (guide coming soon)
+- Understand Best Practices for launching tokens (guide coming soon)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- Learn about [Token Minting](#) in detail
- Explore [NFT Creation](#) features
- Understand [Best Practices](#) for launching tokens
- Learn about Token Minting in detail (guide coming soon)
- Explore NFT Creation features (guide coming soon)
- Understand Best Practices for launching tokens (guide coming soon)
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

65-65: No empty links

(MD042, no-empty-links)


66-66: No empty links

(MD042, no-empty-links)


67-67: No empty links

(MD042, no-empty-links)

🤖 Prompt for AI Agents
In public/docs/getting-started.md around lines 65 to 67 the list items contain
placeholder links with empty URLs; replace each '#' with the correct destination
URL for Token Minting, NFT Creation, and Best Practices (or update to relative
paths if the pages exist in the repo), or remove the square-bracket link markup
and leave plain text if those pages are not ready yet; ensure any added links
are valid, use consistent link style with the rest of the doc, and run a quick
link check/build to confirm there are no remaining placeholders.

- Avoid exploiting issues
- Work with us on fixes

**Contact**: security@example.com (Use PGP key available on our website)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Format bare URLs as proper markdown links.

Bare URLs should be formatted as markdown links for better presentation and accessibility.

Apply this diff:

-**Contact**: security@example.com (Use PGP key available on our website)
+**Contact**: [security@example.com](mailto:security@example.com) (Use PGP key available on our website)

 **Platform Issues:**
-- Support: support@example.com
-- Security: security@example.com
+- Support: [support@example.com](mailto:support@example.com)
+- Security: [security@example.com](mailto:security@example.com)
 - Discord: [Official Channel]

Also applies to: 422-423

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

399-399: Bare URL used

(MD034, no-bare-urls)

🤖 Prompt for AI Agents
In public/docs/privacy-security.md around lines 399 and also apply to lines
422-423, the file contains bare URLs/email contact references that need to be
formatted as proper Markdown links; replace the plain text contact/address
(e.g., security@example.com and any raw URLs) with Markdown link syntax
[security@example.com](mailto:security@example.com) and use [link
text](https://...) for web addresses, ensuring PGP key references link to the
actual PGP key page on the website and update any surrounding text accordingly
for clarity.

Comment on lines +406 to +408
- [Wallet Security Guide](#)
- [Smart Contract Auditing](#)
- [Privacy in Blockchain](#)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Complete or remove placeholder links.

These links have empty URLs and should either be filled in or replaced with text indicating the content is coming soon.

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

406-406: No empty links

(MD042, no-empty-links)


407-407: No empty links

(MD042, no-empty-links)


408-408: No empty links

(MD042, no-empty-links)

🤖 Prompt for AI Agents
In public/docs/privacy-security.md around lines 406 to 408, there are three list
items with placeholder links ("Wallet Security Guide", "Smart Contract
Auditing", "Privacy in Blockchain") pointing to "#" — replace each placeholder
with either a real target URL or remove the anchor and leave plain text headers,
or annotate as “(coming soon)” if content is not yet available; ensure markdown
syntax stays consistent (use plain list items or link format with valid URLs)
and update any related TOC or cross-references to match the chosen approach.

import path from 'path';

// Initialize Gemini AI
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY || '');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Avoid constructing Gemini with an empty API key.

new GoogleGenerativeAI('') throws during module load when GEMINI_API_KEY isn’t set, so the whole route crashes before your 500 guard can run. Instantiate only after confirming the key exists (and cache the client if you need reuse).

-const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY || '');
+let genAI: GoogleGenerativeAI | null = null;
...
-    if (!process.env.GEMINI_API_KEY) {
+    const apiKey = process.env.GEMINI_API_KEY;
+    if (!apiKey) {
       return NextResponse.json(
         { error: 'Gemini API key not configured' },
         { status: 500 }
       );
     }
-
-    // Load all documentation
-    const docsContent = loadAllDocs();
+    if (!genAI) {
+      genAI = new GoogleGenerativeAI(apiKey);
+    }
+
+    // Load all documentation
+    const docsContent = loadAllDocs();
 
     // Initialize the model
-    const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' });
+    const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' });

Also applies to: 52-53

Comment on lines +10 to +13
const { slug } = await params;

// Construct the file path to the markdown file
const filePath = path.join(process.cwd(), 'public', 'docs', `${slug}.md`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

CRITICAL: Path traversal vulnerability - validate and sanitize the slug parameter.

The slug is used directly in file path construction without validation. An attacker could use path traversal sequences like ../../../etc/passwd to read arbitrary files from the server.

Apply this diff to add validation:

   try {
     const { slug } = await params;
+    
+    // Validate slug to prevent path traversal
+    if (!slug || typeof slug !== 'string' || slug.includes('..') || slug.includes('/') || slug.includes('\\')) {
+      return NextResponse.json(
+        { error: 'Invalid documentation slug' },
+        { status: 400 }
+      );
+    }
     
     // Construct the file path to the markdown file
     const filePath = path.join(process.cwd(), 'public', 'docs', `${slug}.md`);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { slug } = await params;
// Construct the file path to the markdown file
const filePath = path.join(process.cwd(), 'public', 'docs', `${slug}.md`);
const { slug } = await params;
// Validate slug to prevent path traversal
if (!slug || typeof slug !== 'string' || slug.includes('..') || slug.includes('/') || slug.includes('\\')) {
return NextResponse.json(
{ error: 'Invalid documentation slug' },
{ status: 400 }
);
}
// Construct the file path to the markdown file
const filePath = path.join(process.cwd(), 'public', 'docs', `${slug}.md`);

Comment on lines +16 to +24
if (!fs.existsSync(filePath)) {
return NextResponse.json(
{ error: 'Documentation not found', path: filePath },
{ status: 404 }
);
}

// Read the markdown file
const content = fs.readFileSync(filePath, 'utf-8');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use async file operations to avoid blocking the event loop.

Synchronous fs.existsSync() and fs.readFileSync() block the Node.js event loop, degrading performance under load. Use async alternatives from fs/promises.

Apply this diff:

-import fs from 'fs';
+import fs from 'fs/promises';
 import path from 'path';
 
 export async function GET(
   request: NextRequest,
   { params }: { params: Promise<{ slug: string }> }
 ) {
   try {
     const { slug } = await params;
     
     // Construct the file path to the markdown file
     const filePath = path.join(process.cwd(), 'public', 'docs', `${slug}.md`);
     
     // Check if file exists
-    if (!fs.existsSync(filePath)) {
+    try {
+      await fs.access(filePath);
+    } catch {
       return NextResponse.json(
-        { error: 'Documentation not found', path: filePath },
+        { error: 'Documentation not found' },
         { status: 404 }
       );
     }
     
     // Read the markdown file
-    const content = fs.readFileSync(filePath, 'utf-8');
+    const content = await fs.readFile(filePath, 'utf-8');
     
     return NextResponse.json({ content }, { status: 200 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!fs.existsSync(filePath)) {
return NextResponse.json(
{ error: 'Documentation not found', path: filePath },
{ status: 404 }
);
}
// Read the markdown file
const content = fs.readFileSync(filePath, 'utf-8');
import fs from 'fs/promises';
import path from 'path';
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ slug: string }> }
) {
try {
const { slug } = await params;
// Construct the file path to the markdown file
const filePath = path.join(process.cwd(), 'public', 'docs', `${slug}.md`);
// Check if file exists
try {
await fs.access(filePath);
} catch {
return NextResponse.json(
{ error: 'Documentation not found' },
{ status: 404 }
);
}
// Read the markdown file
const content = await fs.readFile(filePath, 'utf-8');
return NextResponse.json({ content }, { status: 200 });
}
// ... rest of error handling
}
🤖 Prompt for AI Agents
In src/app/api/docs/[slug]/route.ts around lines 16 to 24, the code uses
synchronous fs.existsSync and fs.readFileSync which block the event loop;
replace them with async fs/promises calls: import the promises API (or require
fs.promises), make the route handler async if it isn't, use await
fs.access(filePath) (or try/catch with fs.stat) to determine existence and
return the 404 response on failure, then use await fs.readFile(filePath,
'utf-8') to read the file, and ensure you catch and handle errors (returning a
404 or 500 as appropriate) instead of blocking IO.

Comment on lines +17 to +18
return NextResponse.json(
{ error: 'Documentation not found', path: filePath },
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Remove file path from error response to prevent information disclosure.

Exposing the server's file path structure in error responses can aid attackers in reconnaissance.

Apply this diff:

       return NextResponse.json(
-        { error: 'Documentation not found', path: filePath },
+        { error: 'Documentation not found' },
         { status: 404 }
       );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return NextResponse.json(
{ error: 'Documentation not found', path: filePath },
return NextResponse.json(
{ error: 'Documentation not found' },
{ status: 404 }
);
🤖 Prompt for AI Agents
In src/app/api/docs/[slug]/route.ts around lines 17 to 18, the error response
currently returns the server file path ({ error: 'Documentation not found',
path: filePath}); remove the path property from the JSON response so the client
only receives a generic error (e.g., { error: 'Documentation not found' }) and,
if needed for debugging, log the filePath server-side using your logger (not in
the HTTP response).

Comment on lines +18 to +20
"before:absolute before:inset-0 before:bg-gradient-to-r before:from-purple-500/20 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
"after:absolute after:top-0 after:left-0 after:w-full after:h-0.5 after:bg-gradient-to-r after:from-purple-500 after:to-transparent",
"after:bottom-0 after:right-0 after:w-0.5 after:h-full after:bg-gradient-to-b after:from-purple-500 after:to-transparent",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Clarify or fix the duplicate after pseudo-element styling.

Line 20 appears to define conflicting after pseudo-element properties (both top-0 left-0 and bottom-0 right-0). A single pseudo-element cannot have multiple positions simultaneously. This may result in only some styles applying.

If you intended to create gradient borders on multiple edges, consider either:

  1. Using separate before and after pseudo-elements for different edges
  2. Using a border-image or gradient border approach
  3. Clarifying the intended visual effect

Please verify this produces the expected visual result.

🤖 Prompt for AI Agents
In src/app/components/ui/button.tsx around lines 18 to 20, the CSS utility
strings define conflicting `after:` pseudo-element positions (one rule sets
top/left, the other sets bottom/right) which cannot both apply to a single
`::after`; pick a consistent plan and change the markup/CSS accordingly: either
keep one `::after` for a single edge (move the other edge's gradient to
`::before` or to a new inner element/span), or implement a true multi-edge
gradient border using border-image/border or an extra element so each gradient
has its own pseudo/element; update the class list and/or component markup so
each pseudo-element only defines one position set and verify the final visual
matches the intended edges.

Comment on lines +165 to +166
snippet = snippet.replace(new RegExp(q, 'ig'), m => `«${m}»`);
results.push({ slug: entry.slug, title: docsSections.find(d => d.slug === entry.slug)?.title || entry.slug, snippet });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Escape the search term before building a RegExp.

Typing characters like [ or ( currently throws a SyntaxError because the raw query is used as the regex pattern. Escape user input before constructing the regex so the search UI can’t crash.

-    const results: { slug: string; title: string; snippet: string }[] = [];
+    const escapedQuery = q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+    const results: { slug: string; title: string; snippet: string }[] = [];
...
-        let snippet = entry.content.slice(start, end).replace(/\n/g, ' ');
-        snippet = snippet.replace(new RegExp(q, 'ig'), m => `«${m}»`);
+        let snippet = entry.content.slice(start, end).replace(/\n/g, ' ');
+        snippet = snippet.replace(new RegExp(escapedQuery, 'ig'), m => `«${m}»`);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/app/docs/page.tsx around lines 165-166, the code builds a RegExp directly
from the raw query `q`, which throws a SyntaxError for special regex characters;
escape the user-provided query before passing it to RegExp (e.g., implement a
small escape routine that replaces regex metacharacters like . * + ? ^ $ { } ( )
| [ ] \ with escaped versions) and then construct the RegExp from the escaped
string (also handle empty/whitespace-only queries by skipping replacement).
Ensure the escaped query is used for both the RegExp constructor and any flags
so user input cannot crash the search UI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant