Help center task 2#1
Conversation
…ons, including project structure, CLI tool, and basic styling. Added .gitignore, package.json, and README.md for project setup and documentation.
…ng for ignored files.
- Introduced ThemeContext for managing light/dark themes. - Updated _app.js to wrap the application in ThemeProvider. - Enhanced Home component to include theme toggle button. - Added dark mode styles in Home.module.css and globals.css. - Updated .coderabbit.yaml with review settings and tool integrations.
WalkthroughIntroduces a Next.js-based Help Center framework with CLI scaffolding, theming via React context, static data and pages for categories and articles, project configuration files, global and module CSS (including dark mode), and a default template configuration. Adds package metadata, Next.js config, gitignore, and documentation. Changes
Sequence Diagram(s)sequenceDiagram
actor U as User
participant C as CLI (help-center.js)
participant FS as File System
participant N as npm
U->>C: help-center create <name>
C->>U: Prompt for title/description
U-->>C: Inputs
C->>FS: Copy templates/default
C->>FS: Write help-center.config.js
C->>N: npm install (in new dir)
N-->>C: Dependencies installed
C-->>U: Print next steps
sequenceDiagram
participant B as Next.js Build
participant D as data.js
participant Cat as /category/[id]
participant Art as /article/[id]
B->>Cat: getStaticPaths()
Cat->>D: read categories
D-->>Cat: categories[]
B->>Cat: getStaticProps({params})
Cat->>D: filter articles by category
D-->>Cat: {category, articles}
B->>Art: getStaticPaths()
Art->>D: read articles
D-->>Art: article ids
B->>Art: getStaticProps({params})
Art->>D: find article + category
D-->>Art: {article, category}
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 12
🧹 Nitpick comments (36)
.gitignore (1)
1-4: Solid baseline ignore list; consider a few Next/Vercel-friendly additionsLooks good. You may want to include common Next.js/Vercel artifacts and broader env patterns.
Apply this diff to extend ignores:
node_modules/ .next/ -.env.local +.env.local +.env.*.local +.env.development.local +.env.test.local +.env.production.local .DS_Store + +# Next.js static export +out/ + +# Vercel +.vercel/ + +# Logs +npm-debug.log* +yarn-error.log* +pnpm-debug.log*next.config.js (1)
1-4: LGTM — strict mode is onConfig is minimal and correct. If you plan to deploy in containers or serverless, consider enabling standalone output.
For example:
/** @type {import('next').NextConfig} */ module.exports = { - reactStrictMode: true + reactStrictMode: true, + output: 'standalone' }styles/globals.css (2)
1-8: Add color-scheme and respect reduced motion
- Add color-scheme to improve native form controls/theming.
- Respect reduced motion to avoid unnecessary transitions for motion-sensitive users.
Apply this diff:
html, body { padding: 0; margin: 0; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; background: #ffffff; color: #111827; - transition: background-color 0.3s ease, color 0.3s ease; + transition: background-color 0.3s ease, color 0.3s ease; + color-scheme: light dark; }And add this block (new code) to reduce motion:
@media (prefers-reduced-motion: reduce) { html, body, a { transition: none !important; } }
10-22: Centralize theming with CSS variables for easier maintenanceManually overriding colors per selector scales poorly. Using CSS variables with a dark-mode override reduces duplication and improves consistency.
Example (outside the selected range) — define variables once:
:root { --bg: #ffffff; --text: #111827; --link: #2563eb; --link-hover: #1d4ed8; } body.dark-mode { --bg: #1a202c; --text: #e2e8f0; --link: #63b3ed; --link-hover: #4299e1; } html, body { background: var(--bg); color: var(--text); } a { color: var(--link); } a:hover { color: var(--link-hover); }README.md (3)
28-41: Project structure in README appears to diverge from the codeREADME shows content/… markdown folders, while the app in this PR uses Next pages with static data (data.js) and a template config under templates/default/.
- If Markdown content will be added later, annotate the README accordingly.
- Otherwise, update the structure to reflect pages/, data.js, context/, templates/, etc.
I can propose an updated tree once you confirm the intended content model.
43-53: Confirm config file location/pathDocs reference help-center.config.js at repo root, but the PR includes templates/default/help-center.config.js. Clarify whether users copy this to root or the loader reads from templates.
If the config is expected at repo root, add that note and a CLI command to scaffold it. I can draft that change to the README.
30-41: Add a language tag to fenced code block to satisfy MD040Specify a language for the directory tree block to appease markdownlint.
-``` +```text my-help-center/ ├── content/ │ ├── docs/ │ ├── api/ │ └── faq/ ├── public/ │ └── img/ ├── styles/ ├── help-center.config.js └── package.json</blockquote></details> <details> <summary>styles/Home.module.css (6)</summary><blockquote> `67-71`: **Use :focus-visible and a stronger accessible focus style** Avoid removing the outline on keyboard focus; prefer :focus-visible with a clear focus ring. ```diff -.search:focus { - outline: none; - border-color: #2563eb; - background-color: white; -} +.search:focus-visible { + outline: 2px solid #2563eb; + outline-offset: 2px; + border-color: #2563eb; + background-color: white; +}
100-103: Avoid transition: all for performanceLimit transitions to the properties that actually change to reduce layout/repaint overhead.
.categoryCard { display: flex; flex-direction: column; padding: 1.5rem; background: white; border: 1px solid #e5e7eb; border-radius: 0.75rem; - transition: all 0.2s ease; + transition: border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease; }
140-143: Avoid !important for SVG sizingPrefer specificity or component-level sizing over !important.
.footerLogo svg { - width: 32px !important; - height: 32px; + width: 32px; + height: 32px; }If specificity conflicts persist, apply a dedicated class to the SVG in JSX and style that class instead of using !important.
195-198: Remove stale TODO commentsDark mode overrides are already implemented below. The TODO block adds noise.
-/* Dark Mode adjustments for Home.module.css */ -/* You might need to add specific dark mode overrides for components in this file */ -/* For example, if a card has a light background, you\'ll want to change it for dark mode */ -
1-5: Consider dvh for mobile viewport issues100vh can cause layout jumps on mobile. Using min-height: 100dvh improves stability where supported.
.container { - min-height: 100vh; + min-height: 100vh; + min-height: 100dvh; display: flex; flex-direction: column; }
199-258: Optional: move dark-mode overrides into globals and/or CSS variablesUsing body.dark-mode selectors inside a CSS module is valid, but centralizing theme tokens in globals (via CSS variables) reduces duplication across modules.
If you adopt variables as suggested in globals.css, most of these overrides become unnecessary; components can rely on var() values instead of per-selector dark-mode rules. I can PR a pass to migrate to tokens if helpful.
.coderabbit.yaml (1)
18-18: Fix YAML lint issues: trailing spaces and missing newline at EOFYAMLlint flagged trailing spaces on blank lines and a missing newline at EOF. These can break strict pipelines.
Apply these minimal fixes:
- + - + - + - Do not omit the closing tags; the docstring must be valid. + Do not omit the closing tags; the docstring must be valid. +Also applies to: 22-22, 28-28, 70-70
templates/default/help-center.config.js (1)
68-68: Trim trailing space and add a newline at EOFMinor formatting fix (prevents noisy diffs and satisfies linters).
-}; +};styles/Category.module.css (3)
32-33: Avoidtransition: all; limit to specific properties for performanceRestrict transitions to properties that actually animate to reduce layout thrashing and improve perf.
- transition: all 0.2s ease; + transition: border-color 0.2s ease, transform 0.2s ease, background-color 0.2s ease, color 0.2s ease;
26-44: Add dark mode overrides to match ThemeContext’s body.dark-modeWithout overrides, white backgrounds and dark text will clash in dark mode. Use CSS Modules’ :global to target the dark-mode body class.
Append these rules:
+/* Dark mode overrides */ +:global(.dark-mode) .articles li { + background: #111827; + border-color: #374151; +} +:global(.dark-mode) .articles li a { + color: #e5e7eb; +} +:global(.dark-mode) .title { + color: #f9fafb; +} +:global(.dark-mode) .description { + color: #9ca3af; +} +:global(.dark-mode) .backLink { + color: #9ca3af; +} +:global(.dark-mode) .backLink:hover { + color: #60a5fa; +}
40-43: Consider link affordances and accessibilityOptional: add text-decoration to clarify interactivity and preserve focus outlines.
.articles li a { color: #111827; font-weight: 500; + text-decoration: none; }context/ThemeContext.js (3)
1-1: Provide a default context value and memoize provider valuePrevents undefined access if used outside a provider and avoids unnecessary re-renders by stabilizing the context value.
-import React, { createContext, useState, useEffect, useContext } from 'react'; +import React, { createContext, useState, useEffect, useContext, useMemo } from 'react'; @@ -const ThemeContext = createContext(); +const ThemeContext = createContext({ theme: 'light', toggleTheme: () => {} }); @@ - return ( - <ThemeContext.Provider value={{ theme, toggleTheme }}> + const value = useMemo(() => ({ theme, toggleTheme }), [theme]); + return ( + <ThemeContext.Provider value={value}> {children} </ThemeContext.Provider> );Also applies to: 3-3, 31-33
10-15: Harden side effects against storage/classList errorsBrowsers may block localStorage or throw on DOM access in edge cases. Wrap in try/catch to avoid breaking the app.
useEffect(() => { - const storedTheme = localStorage.getItem('theme'); - if (storedTheme) { - setTheme(storedTheme); - } + try { + const storedTheme = window?.localStorage?.getItem('theme'); + if (storedTheme) setTheme(storedTheme); + } catch { /* no-op */ } }, []); @@ useEffect(() => { - if (theme === 'dark') { - document.body.classList.add('dark-mode'); - } else { - document.body.classList.remove('dark-mode'); - } - localStorage.setItem('theme', theme); + try { + if (theme === 'dark') { + document?.body?.classList?.add('dark-mode'); + } else { + document?.body?.classList?.remove('dark-mode'); + } + window?.localStorage?.setItem('theme', theme); + } catch { /* no-op */ } }, [theme]);Also applies to: 17-24
7-9: Optional: Prevent dark-mode FOUC on initial loadYou currently default to 'light' then flip to stored 'dark' after mount, causing a flash. Consider an inline script in _document to set the class before hydration.
Add to pages/_document.js within or start:
<script dangerouslySetInnerHTML={{ __html: `(function(){try{var t=localStorage.getItem('theme'); if(t==='dark'){document.documentElement.classList.add('dark-mode');}}catch(e){}})();`, }} />And in CSS, target :global(.dark-mode) on html instead of body for earlier application.
lib/config.js (1)
76-76: Trim trailing space at EOFMinor formatting polish.
-module.exports = new Config(); +module.exports = new Config();data.js (1)
8-15: HTML content in data warrants sanitization downstreamStoring HTML strings in content is fine for a starter dataset, but make sure any rendering uses proper sanitization to prevent XSS. I’ve proposed a fix in pages/article/[articleId].js to sanitize at build-time.
Additionally, if this grows, consider moving to Markdown + a parser (with sanitization) for authoring ergonomics and safer rendering.
styles/Article.module.css (1)
20-35: Dark mode compatibility: add overrides for text colorsThese fixed hex colors will not adapt in dark mode. Since your ThemeProvider toggles body.dark-mode, add dark-mode overrides in this module to improve contrast.
Apply this diff to add dark-mode styles:
.title { font-size: 2rem; font-weight: 600; color: #111827; margin-bottom: 1rem; } + +:global(body.dark-mode) .content { + color: #e5e7eb; +} +:global(body.dark-mode) .title { + color: #f9fafb; +} +:global(body.dark-mode) .backLink { + color: #9ca3af; +} +:global(body.dark-mode) .backLink:hover { + color: #60a5fa; +}pages/article/[articleId].js (1)
10-14: Optional: guard for inconsistent data to avoid build-time crashesGiven paths derive from articles, this should be safe. Still, a lightweight guard improves resilience if data changes.
export async function getStaticProps({ params }) { const article = articles.find(a => a.id === params.articleId); - const category = categories.find(cat => cat.id === article.category); - return { props: { article, category } }; + if (!article) return { notFound: true }; + const category = categories.find(cat => cat.id === article.category); + if (!category) return { notFound: true }; + return { props: { article, category } }; }pages/category/[categoryId].js (2)
10-14: Return 404 when category not found (defensive SSG)Paths come from categories so this is typically safe, but a simple guard prevents undefined access if data diverges.
export async function getStaticProps({ params }) { const category = categories.find(cat => cat.id === params.categoryId); - const categoryArticles = articles.filter(article => article.category === category.id); - return { props: { category, articles: categoryArticles } }; + if (!category) return { notFound: true }; + const categoryArticles = articles.filter(article => article.category === category.id); + return { props: { category, articles: categoryArticles } }; }
1-4: Set page title and description for SEOAdd with a dynamic title/description.
-import Link from 'next/link'; +import Link from 'next/link'; +import Head from 'next/head';return ( <div className={styles.container}> + <Head> + <title>{category.title} - Help Center</title> + <meta name="description" content={category.description} /> + </Head> <Link href="/" className={styles.backLink}>← Back to Home</Link>package.json (3)
25-25: Update chalk to latest version for Node.js compatibility.Chalk version 4.1.2 may have compatibility issues with newer Node.js versions. Consider updating to the latest version for better compatibility.
- "chalk": "^4.1.2", + "chalk": "^5.3.0",
27-27: Update inquirer to latest ESM version.Inquirer 8.2.5 is outdated and may have compatibility issues. The latest version provides better TypeScript support and ESM compatibility.
- "inquirer": "^8.2.5", + "inquirer": "^9.2.12",
44-44: Add author information.The author field is empty, which should be filled in for proper package attribution.
- "author": "", + "author": "Your Name <your.email@example.com>",bin/help-center.js (1)
84-86: Implement deployment functionality.The deploy command is currently a placeholder and needs implementation.
The deploy command currently has no implementation. Would you like me to help implement deployment logic for common platforms like Vercel, Netlify, or GitHub Pages?
pages/index.js (5)
29-31: Optimize search performance for large datasets.The current search implementation filters all articles on every keystroke, which could become inefficient with large datasets.
Consider implementing debounced search or moving the filtering logic into a useMemo hook:
+import { useState, useMemo } from 'react'; + export default function Home() { const [query, setQuery] = useState(''); const { theme, toggleTheme } = useTheme(); - const filteredArticles = articles.filter(article => - article.title.toLowerCase().includes(query.toLowerCase()) - ); + + const filteredArticles = useMemo(() => { + if (!query.trim()) return []; + return articles.filter(article => + article.title.toLowerCase().includes(query.toLowerCase().trim()) + ); + }, [query]);
36-36: Make branding configurable.The hardcoded "Acme Corp" branding should be configurable through the help center configuration.
Consider importing and using configuration values:
+import config from '../help-center.config'; + - <Link href="/" className={styles.logo}>Acme Corp</Link> + <Link href="/" className={styles.logo}>{config?.title || 'Help Center'}</Link>
77-77: Optimize category article counting.The current implementation filters articles for each category separately, which could be inefficient with many categories.
Consider pre-computing article counts:
+ const articleCounts = useMemo(() => { + return articles.reduce((acc, article) => { + acc[article.category] = (acc[article.category] || 0) + 1; + return acc; + }, {}); + }, []); + {categories.map(cat => { - const categoryArticles = articles.filter(article => article.category === cat.id); + const articleCount = articleCounts[cat.id] || 0; return ( <Link key={cat.id} href={`/category/${cat.id}`} className={styles.categoryCard}> <div className={styles.icon}> <FontAwesomeIcon icon={iconMap[cat.icon]} /> </div> <h2>{cat.title}</h2> <p>{cat.description}</p> <div className={styles.articleCount}> - {categoryArticles.length} articles + {articleCount} articles </div> </Link> ); })}
99-102: Make footer navigation configurable.The hardcoded footer navigation links should be configurable or at least more generic for a help center framework.
Consider making these links configurable or using more generic help center navigation:
<nav className={styles.footerNav}> - <Link href="/chatgpt" className={styles.footerLink}>ChatGPT</Link> - <Link href="/api" className={styles.footerLink}>API</Link> - <Link href="/dall-e" className={styles.footerLink}>DALL·E</Link> + <Link href="/contact" className={styles.footerLink}>Contact</Link> + <Link href="/help" className={styles.footerLink}>Help</Link> + <Link href="/privacy" className={styles.footerLink}>Privacy</Link> <Link href="/status" className={styles.footerLink}>Service Status</Link> </nav>
105-111: Make social links configurable.The hardcoded social media links should be configurable through the help center configuration.
Consider making social links configurable:
+ {config?.socialLinks && ( <div className={styles.socialLinks}> - <a href="https://twitter.com/acmecorp" target="_blank" rel="noopener noreferrer" className={styles.socialIcon}> - <FontAwesomeIcon icon={faTwitter} /> - </a> - <a href="https://linkedin.com/company/acmecorp" target="_blank" rel="noopener noreferrer" className={styles.socialIcon}> - <FontAwesomeIcon icon={faLinkedin} /> - </a> + {config.socialLinks.twitter && ( + <a href={config.socialLinks.twitter} target="_blank" rel="noopener noreferrer" className={styles.socialIcon}> + <FontAwesomeIcon icon={faTwitter} /> + </a> + )} + {config.socialLinks.linkedin && ( + <a href={config.socialLinks.linkedin} target="_blank" rel="noopener noreferrer" className={styles.socialIcon}> + <FontAwesomeIcon icon={faLinkedin} /> + </a> + )} </div> + )}
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (18)
.coderabbit.yaml(1 hunks).gitignore(1 hunks)README.md(1 hunks)bin/help-center.js(1 hunks)context/ThemeContext.js(1 hunks)data.js(1 hunks)lib/config.js(1 hunks)next.config.js(1 hunks)package.json(1 hunks)pages/_app.js(1 hunks)pages/article/[articleId].js(1 hunks)pages/category/[categoryId].js(1 hunks)pages/index.js(1 hunks)styles/Article.module.css(1 hunks)styles/Category.module.css(1 hunks)styles/Home.module.css(1 hunks)styles/globals.css(1 hunks)templates/default/help-center.config.js(1 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
styles/globals.css
[error] 4-4: Duplicate font names are redundant and unnecessary: Sans
Remove duplicate font names within the property
(lint/suspicious/noDuplicateFontNames)
pages/article/[articleId].js
[error] 21-21: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🪛 LanguageTool
README.md
[grammar] ~8-~8: There might be a mistake here.
Context: ...tures - 🚀 Quick setup with CLI tool - 📝 Markdown-based content - 🎨 Customizabl...
(QB_NEW_EN)
[grammar] ~9-~9: There might be a mistake here.
Context: ...LI tool - 📝 Markdown-based content - 🎨 Customizable themes - 🔍 Built-in search...
(QB_NEW_EN)
[grammar] ~10-~10: There might be a mistake here.
Context: ...d content - 🎨 Customizable themes - 🔍 Built-in search - 📱 Mobile-responsive - ...
(QB_NEW_EN)
[grammar] ~11-~11: There might be a mistake here.
Context: ...zable themes - 🔍 Built-in search - 📱 Mobile-responsive - 🌐 SEO-friendly - 🔄 E...
(QB_NEW_EN)
[grammar] ~12-~12: There might be a mistake here.
Context: ...in search - 📱 Mobile-responsive - 🌐 SEO-friendly - 🔄 Easy deployment to any do...
(QB_NEW_EN)
[grammar] ~13-~13: There might be a mistake here.
Context: ...le-responsive - 🌐 SEO-friendly - 🔄 Easy deployment to any domain ## Quick Star...
(QB_NEW_EN)
[grammar] ~15-~15: There might be a mistake here.
Context: ... Easy deployment to any domain ## Quick Start ```bash # Create a new help center...
(QB_NEW_EN)
[grammar] ~88-~88: There might be a mistake here.
Context: ...hat you can customize: 1. Default theme 2. Dark theme 3. Custom themes (create your...
(QB_NEW_EN)
[grammar] ~89-~89: There might be a mistake here.
Context: ...stomize: 1. Default theme 2. Dark theme 3. Custom themes (create your own) ### Cus...
(QB_NEW_EN)
🪛 markdownlint-cli2 (0.17.2)
README.md
30-30: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🪛 YAMLlint (1.37.1)
.coderabbit.yaml
[error] 18-18: trailing spaces
(trailing-spaces)
[error] 22-22: trailing spaces
(trailing-spaces)
[error] 28-28: trailing spaces
(trailing-spaces)
[error] 70-70: no new line character at the end of file
(new-line-at-end-of-file)
🔇 Additional comments (9)
.coderabbit.yaml (1)
29-46: Tooling selection looks sane for this stackast-grep, eslint, markdownlint, biome, and gitleaks enabled by default is a good baseline here.
templates/default/help-center.config.js (1)
14-31: Config structure is consistent and clearNav items and footer links are well-structured with internal routes via "to" and external via "href". This aligns with the Config shape used elsewhere.
Also applies to: 37-47
lib/config.js (2)
24-46: Default config shape is robust and matches the templateConsistent fields across title, baseUrl, navbar, and footer. Good baseline for consumers.
13-13: Optional: Consider ESM config supportIf a consumer provides an ESM config (export default), require will throw ERR_REQUIRE_ESM. Supporting both would require async dynamic import; if you need this, I can propose an async loader variant.
Would you like ESM config files to be supported (e.g., help-center.config.mjs)? If yes, I can provide a backwards-compatible async loader.
data.js (1)
1-6: Static data model looks coherent and consumablecategories define stable ids and metadata suitable for static path generation and UI rendering. No issues spotted.
pages/_app.js (1)
1-7: Correct Font Awesome setup and global provider wiringImport order and config.autoAddCss = false are correct for Next.js + Font Awesome. ThemeProvider wrapping the app is clean.
pages/article/[articleId].js (1)
19-21: No changes needed: Next.js v13+ supports className onWe’ve confirmed from package.json that the project is using Next.js v13.4.7, so the
classNameprop on<Link>is fully supported. No updates required here.pages/category/[categoryId].js (1)
19-26: Next.js Link className compatibilitySame note as the article page: className on Link needs Next 13+. If on 12, use .
Use the same script provided in the article page comment to check the Next version and, if needed, adopt legacy behavior:
- <Link href="/" className={styles.backLink}>← Back to Home</Link> + <Link href="/"><a className={styles.backLink}>← Back to Home</a></Link>package.json (1)
21-23: Confirmed: Next.js 13.4.7 Is Compatible with React 18.2.0
Next.js 13.x requires React 18.2.0 (or newer) for full feature support, and 13.4.7 has been tested against React 18.2.0 with no known incompatibilities. No changes are needed to your specified versions.
| chat: | ||
| auto_reply: true | ||
| create_issues: true | ||
|
|
There was a problem hiding this comment.
Invalid key "chat.create_issues" violates the published schema
The chat block only allows: art, auto_reply, and integrations. "create_issues" is not part of the schema and will cause validation failures.
Apply this diff to remove the invalid key (and optionally enable integrations if desired):
chat:
auto_reply: true
- create_issues: true
+ integrations:
+ jira:
+ usage: auto
+ linear:
+ usage: auto📝 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.
| chat: | |
| auto_reply: true | |
| create_issues: true | |
| chat: | |
| auto_reply: true | |
| integrations: | |
| jira: | |
| usage: auto | |
| linear: | |
| usage: auto |
🤖 Prompt for AI Agents
In .coderabbit.yaml around lines 48 to 51 the chat section contains an invalid
key "create_issues" which violates the schema; remove the "create_issues: true"
line from the chat block and, if issue creation is intended, replace it with a
valid "integrations:" configuration per the schema (or set "integrations: true"
if supported) so the chat block only contains allowed keys (art, auto_reply,
integrations).
| const projectPath = path.join(process.cwd(), projectName); | ||
|
|
||
| // Create project directory | ||
| fs.mkdirSync(projectPath, { recursive: true }); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add error handling for directory creation.
The mkdirSync call doesn't handle cases where the directory already exists or permission issues occur.
- fs.mkdirSync(projectPath, { recursive: true });
+ try {
+ if (fs.existsSync(projectPath)) {
+ console.error(chalk.red(`Error: Directory ${projectName} already exists.`));
+ process.exit(1);
+ }
+ fs.mkdirSync(projectPath, { recursive: true });
+ } catch (error) {
+ console.error(chalk.red(`Error creating directory: ${error.message}`));
+ process.exit(1);
+ }📝 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.
| fs.mkdirSync(projectPath, { recursive: true }); | |
| try { | |
| if (fs.existsSync(projectPath)) { | |
| console.error(chalk.red(`Error: Directory ${projectName} already exists.`)); | |
| process.exit(1); | |
| } | |
| fs.mkdirSync(projectPath, { recursive: true }); | |
| } catch (error) { | |
| console.error(chalk.red(`Error creating directory: ${error.message}`)); | |
| process.exit(1); | |
| } |
🤖 Prompt for AI Agents
In bin/help-center.js around line 38, the fs.mkdirSync(projectPath, { recursive:
true }) call lacks error handling; wrap this call in a try/catch, catch any
thrown error, handle benign cases (with recursive: true EEXIST should not occur
but still guard) and for other errors (e.g. EACCES, EPERM) log a clear error
message including the error.stack or message and exit the process with a
non-zero code (or rethrow if upstream handles it); ensure the catch
distinguishes permission/IO errors and provides actionable logging before
exiting.
| const templatePath = path.join(__dirname, '../templates/default'); | ||
| fs.copySync(templatePath, projectPath); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add error handling for template copying.
The template copying operation should handle cases where the template directory doesn't exist or copying fails.
- const templatePath = path.join(__dirname, '../templates/default');
- fs.copySync(templatePath, projectPath);
+ const templatePath = path.join(__dirname, '../templates/default');
+ try {
+ if (!fs.existsSync(templatePath)) {
+ console.error(chalk.red('Error: Template directory not found.'));
+ process.exit(1);
+ }
+ fs.copySync(templatePath, projectPath);
+ } catch (error) {
+ console.error(chalk.red(`Error copying template: ${error.message}`));
+ process.exit(1);
+ }📝 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.
| const templatePath = path.join(__dirname, '../templates/default'); | |
| fs.copySync(templatePath, projectPath); | |
| const templatePath = path.join(__dirname, '../templates/default'); | |
| try { | |
| if (!fs.existsSync(templatePath)) { | |
| console.error(chalk.red('Error: Template directory not found.')); | |
| process.exit(1); | |
| } | |
| fs.copySync(templatePath, projectPath); | |
| } catch (error) { | |
| console.error(chalk.red(`Error copying template: ${error.message}`)); | |
| process.exit(1); | |
| } |
🤖 Prompt for AI Agents
In bin/help-center.js around lines 41 to 42, the code copies a template
directory with fs.copySync without handling errors or missing source; wrap the
copy operation in a try/catch (or check fs.existsSync(templatePath) first) and
on failure log a clear error and exit with non‑zero status; ensure the error
handler distinguishes "template not found" vs "copy failed" and includes the
actual error message for debugging.
| fs.writeFileSync( | ||
| path.join(projectPath, 'help-center.config.js'), | ||
| `module.exports = ${JSON.stringify(config, null, 2)}` | ||
| ); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add error handling for config file creation.
The config file writing should handle potential filesystem errors.
- fs.writeFileSync(
- path.join(projectPath, 'help-center.config.js'),
- `module.exports = ${JSON.stringify(config, null, 2)}`
- );
+ try {
+ fs.writeFileSync(
+ path.join(projectPath, 'help-center.config.js'),
+ `module.exports = ${JSON.stringify(config, null, 2)}`
+ );
+ } catch (error) {
+ console.error(chalk.red(`Error creating config file: ${error.message}`));
+ process.exit(1);
+ }📝 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.
| fs.writeFileSync( | |
| path.join(projectPath, 'help-center.config.js'), | |
| `module.exports = ${JSON.stringify(config, null, 2)}` | |
| ); | |
| try { | |
| fs.writeFileSync( | |
| path.join(projectPath, 'help-center.config.js'), | |
| `module.exports = ${JSON.stringify(config, null, 2)}` | |
| ); | |
| } catch (error) { | |
| console.error(chalk.red(`Error creating config file: ${error.message}`)); | |
| process.exit(1); | |
| } |
🤖 Prompt for AI Agents
In bin/help-center.js around lines 53 to 56, the call to fs.writeFileSync that
writes help-center.config.js lacks error handling; wrap the write in a try/catch
(or use the async fs.promises API) to catch filesystem errors, log a clear error
message including the target path and the caught error (e.g., console.error or a
logger), and exit with a non‑zero status (process.exit(1)) so failures are not
silently ignored; also ensure the target directory exists before writing (create
it if necessary) to prevent EEXIST/ENOENT failures.
|
|
||
| // Install dependencies | ||
| console.log(chalk.yellow('Installing dependencies...')); | ||
| execSync('npm install', { cwd: projectPath, stdio: 'inherit' }); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add error handling for npm installation.
The npm install command should handle installation failures gracefully.
- execSync('npm install', { cwd: projectPath, stdio: 'inherit' });
+ try {
+ execSync('npm install', { cwd: projectPath, stdio: 'inherit' });
+ } catch (error) {
+ console.error(chalk.red('Error installing dependencies. Please run npm install manually.'));
+ console.log(chalk.green('\nProject created at ' + projectPath));
+ process.exit(1);
+ }Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In bin/help-center.js around line 60, the execSync('npm install', { cwd:
projectPath, stdio: 'inherit' }) call lacks error handling; wrap the install in
a try/catch, run execSync inside the try, catch errors and log a clear error
message including the caught error and projectPath, and exit the process with a
non-zero code (e.g., process.exit(1)) to fail gracefully on installation
failure.
| <div className={styles.container}> | ||
| <Link href={`/category/${category.id}`} className={styles.backLink}>← {category.title}</Link> | ||
| <h1 className={styles.title}>{article.title}</h1> | ||
| <div className={styles.content} dangerouslySetInnerHTML={{ __html: article.content }} /> |
There was a problem hiding this comment.
Sanitize HTML before using dangerouslySetInnerHTML (XSS risk)
Rendering raw HTML from data exposes XSS risk. Sanitize the content before injection and annotate for Biome.
Apply the following diffs:
- Import DOMPurify
import Link from 'next/link';
import { categories, articles } from '../../data';
import styles from '../../styles/Article.module.css';
+import DOMPurify from 'isomorphic-dompurify';- Sanitize during SSG in getStaticProps so the client never receives unsafe HTML
export async function getStaticProps({ params }) {
- const article = articles.find(a => a.id === params.articleId);
- const category = categories.find(cat => cat.id === article.category);
- return { props: { article, category } };
+ const article = articles.find(a => a.id === params.articleId);
+ const category = categories.find(cat => cat.id === article?.category);
+ const sanitizedContent = article ? DOMPurify.sanitize(article.content) : '';
+ return {
+ props: {
+ article: article ? { ...article, content: sanitizedContent } : null,
+ category: category || null
+ }
+ };
}- Keep the render but annotate the line for Biome since we sanitize input
- <div className={styles.content} dangerouslySetInnerHTML={{ __html: article.content }} />
+ {/* biome-ignore lint/security/noDangerouslySetInnerHtml: content sanitized in getStaticProps */}
+ <div className={styles.content} dangerouslySetInnerHTML={{ __html: article.content }} />📝 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.
| <div className={styles.content} dangerouslySetInnerHTML={{ __html: article.content }} /> | |
| // pages/article/[articleId].js | |
| import Link from 'next/link'; | |
| import { categories, articles } from '../../data'; | |
| import styles from '../../styles/Article.module.css'; | |
| import DOMPurify from 'isomorphic-dompurify'; | |
| export async function getStaticProps({ params }) { | |
| const article = articles.find(a => a.id === params.articleId); | |
| const category = categories.find(cat => cat.id === article?.category); | |
| const sanitizedContent = article ? DOMPurify.sanitize(article.content) : ''; | |
| return { | |
| props: { | |
| article: article ? { ...article, content: sanitizedContent } : null, | |
| category: category || null | |
| } | |
| }; | |
| } | |
| export default function ArticlePage({ article, category }) { | |
| return ( | |
| <div className={styles.container}> | |
| {/* other article details here */} | |
| {/* biome-ignore lint/security/noDangerouslySetInnerHtml: content sanitized in getStaticProps */} | |
| <div | |
| className={styles.content} | |
| dangerouslySetInnerHTML={{ __html: article.content }} | |
| /> | |
| </div> | |
| ); | |
| } |
🧰 Tools
🪛 Biome (2.1.2)
[error] 21-21: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🤖 Prompt for AI Agents
In pages/article/[articleId].js around line 21, the component is rendering raw
HTML directly into dangerouslySetInnerHTML which risks XSS; import DOMPurify at
the top, sanitize article.content in getStaticProps (or the SSG step) by running
DOMPurify.sanitize(...) and return the sanitized HTML to the page so the client
never receives unsafe markup, then keep the render using dangerouslySetInnerHTML
but add a comment/annotation for Biome (e.g., /* biome-ignore-next-line */) on
that line to indicate it's safe because the content was sanitized server-side.
| const iconMap = { | ||
| 'rocket': faRocket, | ||
| 'book': faBook, | ||
| 'credit-card': faCreditCard, | ||
| 'code': faCode | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add fallback for missing category icons.
The iconMap doesn't handle cases where a category has an icon that's not defined in the mapping, which could cause runtime errors.
+import { faQuestion } from '@fortawesome/free-solid-svg-icons';
+
const iconMap = {
'rocket': faRocket,
'book': faBook,
'credit-card': faCreditCard,
- 'code': faCode
+ 'code': faCode,
+ 'default': faQuestion
};Then update the icon usage:
- <FontAwesomeIcon icon={iconMap[cat.icon]} />
+ <FontAwesomeIcon icon={iconMap[cat.icon] || iconMap.default} />📝 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.
| const iconMap = { | |
| 'rocket': faRocket, | |
| 'book': faBook, | |
| 'credit-card': faCreditCard, | |
| 'code': faCode | |
| }; | |
| // Add at the top alongside your other icon imports | |
| import { faQuestion } from '@fortawesome/free-solid-svg-icons'; | |
| const iconMap = { | |
| 'rocket': faRocket, | |
| 'book': faBook, | |
| 'credit-card': faCreditCard, | |
| 'code': faCode, | |
| 'default': faQuestion | |
| }; | |
| // …later in your JSX… | |
| <FontAwesomeIcon icon={iconMap[cat.icon] || iconMap.default} /> |
🤖 Prompt for AI Agents
In pages/index.js around lines 19 to 24, the iconMap currently lists specific
icons but has no fallback for unknown category keys; update iconMap to include a
default/fallback key (e.g., 'default' mapped to a generic icon you already
import or add such an import), and change icon resolution where the map is used
to select iconMap[category] || iconMap['default'] (or the default variable) so
unknown or missing category icons won't cause runtime errors.
| ```bash | ||
| # Create a new help center | ||
| npx help-center-framework create my-help-center | ||
|
|
||
| # Navigate to the project | ||
| cd my-help-center | ||
|
|
||
| # Start the development server | ||
| npm run dev | ||
| ``` |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify CLI package name and bin linkage in package.json
The command uses “npx help-center-framework”. Ensure the published package name and the bin entry align so this works when installed globally or via npx.
Run this script to confirm the package/bin mapping:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Package name and bin entries:"
if command -v jq >/dev/null 2>&1; then
jq '{name, bin}' package.json
else
echo "jq not found; printing package.json snippet:"
sed -n '1,120p' package.json
fi
echo
echo "Check that 'help-center-framework' is either the package name or a key under .bin"Length of output: 419
Fix CLI invocation or bin alias in package.json
The package.json bin entry is currently:
"bin": {
"help-center": "./bin/help-center.js"
}So running npx help-center-framework will fail because there’s no help-center-framework key under bin. You can address this by either:
- Updating the README snippet to:
npx help-center
- Or adding an alias in package.json:
"bin": { "help-center": "./bin/help-center.js",
- "help-center-framework": "./bin/help-center.js"
}
Please choose one approach and apply it to align the CLI invocation with the bin mapping.
<details>
<summary>🤖 Prompt for AI Agents</summary>
In README.md around lines 17 to 26, the CLI invocation currently uses npx
help-center-framework which does not match the package.json bin mapping
("help-center": "./bin/help-center.js"); update the README to use npx
help-center instead of npx help-center-framework so the example matches the bin
alias, and ensure any subsequent README instructions reference the same CLI
name.
</details>
<!-- fingerprinting:phantom:poseidon:chinchilla -->
<!-- This is an auto-generated comment by CodeRabbit -->
| ## Deployment | ||
|
|
||
| 1. Build your help center: | ||
| ```bash | ||
| npm run build | ||
| ``` | ||
|
|
||
| 2. Deploy to your domain: | ||
| ```bash | ||
| npm run deploy | ||
| ``` | ||
|
|
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify presence of build/deploy npm scripts
Ensure npm run deploy exists and matches your deployment target (Vercel, static export, etc.).
Run this script to confirm:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Available scripts:"
if command -v jq >/dev/null 2>&1; then
jq -r '.scripts' package.json
else
sed -n '1,200p' package.json | sed -n '/"scripts": {/,/}/p'
fiLength of output: 234
Update README or Add Missing “deploy” Script
The README instructs users to run npm run deploy, but there is no deploy script defined in package.json. You should either:
- Add a
deployentry under"scripts"in package.json (pointing to your actual deployment command), for example:"scripts": { "deploy": "your-deploy-command-here", … }
- Or update the README to reference an existing script (e.g.
npm run startor whatever matches your deploy workflow).
Locations to address:
- README.md, lines 70–81: change “npm run deploy” to the correct script or add instructions for installing/defining the deploy script.
- package.json: add
"deploy": "...“under"scripts"if you choose to define the script.
🤖 Prompt for AI Agents
In README.md around lines 70 to 81, the docs reference running "npm run deploy"
but there is no deploy script in package.json; either add a "deploy" entry under
"scripts" in package.json that runs your actual deployment command (e.g., your
hosting provider CLI or build-and-publish steps) or update the README to call an
existing script (for example "npm run start" or the build command) and include
any required install/authorization steps; make the change in README.md to
reflect the chosen workflow and, if adding a script, insert a "deploy" script
into package.json under "scripts" pointing to the real deployment command.
| description: 'Documentation and Support', | ||
| theme: 'default', | ||
| baseUrl: '/', | ||
| favicon: 'img/favicon.ico', |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Use absolute asset URLs to avoid broken paths on nested routes
Relative paths like "img/logo.svg" resolve relative to the current route (e.g., /category/xyz), causing 404s. Use absolute paths or prefix with baseUrl.
Apply:
- favicon: 'img/favicon.ico',
+ favicon: '/img/favicon.ico',
@@
- src: 'img/logo.svg',
+ src: '/img/logo.svg',Also applies to: 11-11
🤖 Prompt for AI Agents
In templates/default/help-center.config.js around lines 6 and 11, the config
uses relative asset paths (e.g., "img/favicon.ico") which break on nested
routes; update those values to use absolute asset URLs or construct them with
the site's baseUrl (or prefix with a leading slash) so they resolve from the
site root rather than the current route.
Task assignment 2
Summary by CodeRabbit