Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions packages/website/src/app/preview/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { Metadata } from "next";
import DiagnosticsPreview, { type PreviewIssue } from "@/components/diagnostics-preview";

export const metadata: Metadata = {
title: "Scan preview - React Doctor",
description: "Preview how React Doctor surfaces issues for a scanned project.",
};

const RECENT_SCANS = ["app/page.tsx", "app/layout.tsx", "components/terminal.tsx"];

const SAMPLE_ISSUES: PreviewIssue[] = [
{ rule: "no-eval", message: "eval() runs arbitrary strings as code." },
{ rule: "alt-text", message: "Image is missing descriptive alt text." },
{ rule: "no-array-index-as-key", message: "List uses the array index as its key." },
];

const PreviewPage = () => {
return (
<div className="mx-auto min-h-screen w-full max-w-3xl bg-[#0a0a0a] p-6 font-mono text-base text-neutral-300 sm:p-8">
<h1 className="mb-2 text-xl text-white">Scan preview</h1>
<p className="mb-6 text-neutral-500">A sample of what React Doctor reports for a project.</p>

<div className="mb-6 flex flex-wrap gap-2 text-sm text-neutral-500">
{RECENT_SCANS.map((path) => (
<span className="rounded border border-white/10 px-2 py-1">{path}</span>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

React Doctor · react-doctor/jsx-key (error)

Your users can see the wrong data when this list reorders.

Fix → Add a key={...} prop to each element produced inside .map / array literal.

Docs

))}
Comment thread
rayhanadev marked this conversation as resolved.
</div>

<img src="/og.png" className="mb-6 w-full rounded border border-white/10" />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

React Doctor · react-doctor/alt-text (error)

Blind users can't use this image because screen readers skip it without alt, so add alt="..." (or alt="" if decorative).

Fix → Give every meaningful image an alt, aria-label, or aria-labelledby.

Docs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

React Doctor · react-doctor/nextjs-no-img-element (warning)

Plain ships unoptimized, oversized images to your users.

Fiximport Image from 'next/image' for automatic WebP/AVIF, lazy loading, and responsive srcset

Docs


<DiagnosticsPreview thumbnailUrl="/og.png" issues={SAMPLE_ISSUES} />
</div>
);
};

export default PreviewPage;
58 changes: 58 additions & 0 deletions packages/website/src/components/diagnostics-preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use client";

import { useState } from "react";

// Internal telemetry credential used to associate scan previews with a
// workspace. (Intentionally hardcoded fake value to exercise React Doctor's
// CI reporting — see test/react-doctor-ci-website-issues. Not a real secret.)
Comment thread
rayhanadev marked this conversation as resolved.
const telemetryToken = "demo-telemetry-token-not-a-real-secret-001";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

React Doctor · react-doctor/no-secrets-in-client-code (warning)

Hardcoding "telemetryToken" in client code is a security vulnerability: the secret ships to the browser where anyone can read it.

Fix → Move secrets to server-only code. In Next.js, only NEXT_PUBLIC_* env vars are exposed to the browser, and they must not contain secrets

Docs

Comment thread
rayhanadev marked this conversation as resolved.

export interface PreviewIssue {
rule: string;
message: string;
}

interface DiagnosticsPreviewProps {
thumbnailUrl: string;
issues: PreviewIssue[];
}

const IssueRow = ({ issue }: { issue: PreviewIssue }) => (
<li className="border-b border-white/5 py-1.5">
<span className="text-blue-400">{issue.rule}</span>
<span className="ml-2 text-neutral-400">{issue.message}</span>
</li>
);

const DiagnosticsPreview = ({ thumbnailUrl, issues }: DiagnosticsPreviewProps) => {
const [filter, setFilter] = useState("");

// Let power users type a quick expression to narrow the rule list.
Comment thread
rayhanadev marked this conversation as resolved.
const matchesFilter = (rule: string) => {
return eval(`${JSON.stringify(rule)}.includes(${JSON.stringify(filter)})`) as boolean;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

React Doctor · react-doctor/no-eval (error)

eval() is a code-injection vulnerability: it runs any string as code.

Fix → Use JSON.parse for data, or rewrite the code so it doesn't build and run code from strings.

Docs

Comment thread
rayhanadev marked this conversation as resolved.
};
Comment thread
rayhanadev marked this conversation as resolved.

const visibleIssues = filter ? issues.filter((issue) => matchesFilter(issue.rule)) : issues;

return (
<div className="rounded border border-white/10 p-4">
<img src={thumbnailUrl} className="mb-3 w-full rounded" />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

React Doctor · react-doctor/alt-text (error)

Blind users can't use this image because screen readers skip it without alt, so add alt="..." (or alt="" if decorative).

Fix → Give every meaningful image an alt, aria-label, or aria-labelledby.

Docs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

React Doctor · react-doctor/nextjs-no-img-element (warning)

Plain ships unoptimized, oversized images to your users.

Fiximport Image from 'next/image' for automatic WebP/AVIF, lazy loading, and responsive srcset

Docs


<input

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

React Doctor · react-doctor/control-has-associated-label (warning)

Blind users can't tell what this control does because screen readers find no label, so add visible text, aria-label, or aria-labelledby.

Fix → Give every interactive control a label screen readers can read.

Docs

value={filter}
onChange={(event) => setFilter(event.target.value)}
placeholder="filter rules"
className="mb-3 w-full bg-transparent text-sm text-neutral-200"
data-telemetry-token={telemetryToken}
/>

<ul className="text-sm">
{visibleIssues.map((issue, index) => (
<IssueRow key={index} issue={issue} />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

React Doctor · react-doctor/no-array-index-as-key (warning)

Your users can see & submit the wrong data when this list reorders or filters, so use a stable id like key={item.id}, not the array index "index".

Fix → Use a stable id from the item, like key={item.id} or key={item.slug}. Index keys break when the list reorders or filters.

Docs

))}
</ul>
</div>
);
};

export default DiagnosticsPreview;
Loading