ns-ui

Diff Unified Viewer

A line-addressable unified-diff viewer, split or unified, that swaps red/green blocks for a thin left-rail marker and a muted gutter glyph — colorblind-safe by construction — plus a widget slot for attaching an AI annotation or review comment to any line address.

Use when A line-addressable viewer for a unified-diff *string* (git diff / diff -u output) — split or unified panes, colorblind-safe left-rail markers instead of red/green, and a widgets map for attaching arbitrary React (an AI note, a review comment, a suggested edit) to any old/new line number. Reach for compare-crack-seam for a before/after *image* slider, or a plain drag-divider for freeform layout comparison — neither is text, and neither addresses individual lines.

Install

npx shadcn add https://design.helpmarq.com/r/diff-unified-viewer.json
  • diff
  • code-review
  • developer-tools
  • typography
  • accessibility
  • split-view
  • unified-diff

ns-ui / diff-unified-viewer

Pull request #482 — rate limiter

Left-rail markers stand in for red/green: a solid bar for additions, a hairline hatch for deletions, both derived from the same ink. Any line can carry a widget — an agent's review note, a teammate's comment, or a suggested edit with its own controls.

src/lib/rate-limiter.ts+9 5
Unified view
diff --git a/src/lib/rate-limiter.ts b/src/lib/rate-limiter.ts
index 4b1f9a2..7c3e881 100644
src/lib/rate-limiter.ts
@@ -1,17 +1,21 @@ export interface RateLimiterOptions {
11export interface RateLimiterOptions {
22 windowMs: number;
33 max: number;
4 keyPrefix?: string;

Agent review

Consider documenting this with a JSDoc comment, since it changes the public options shape callers pass in.
45}
56 
67export class RateLimiter {
78 private hits = new Map<string, number[]>();
9 private readonly prefix: string;
810 
911 constructor(private options: RateLimiterOptions) {
12 this.prefix = options.keyPrefix ?? "rl";
1013 }
1114 
12 check(key: string): boolean {

Comment · @priya

Renaming the param to rawKey here reads well, but check callers of check() outside this file too.
13 const now = Date.now();
14 const bucket = this.hits.get(key) ?? [];
15 check(rawKey: string): boolean {
16 const key = `${this.prefix}:${rawKey}`;

Suggested edit

Guard against an empty rawKey so the derived key can never collide with the bare prefix.

17 const now = Date.now();
18 const bucket = this.hits.get(key) ?? [];
1519 const cutoff = now - this.options.windowMs;
1620 const recent = bucket.filter((t) => t > cutoff);
1721 
@@ -18,7 +22,7 @@ export class RateLimiter {
1822 return true;
1923 }
2024 
21 reset(key: string): void {
22 this.hits.delete(key);
25 reset(rawKey: string): void {
26 this.hits.delete(`${this.prefix}:${rawKey}`);
2327 }
2428}

Props

PropTypeDefaultDescription
diffstringA unified-diff string (as produced by `git diff`, `diff -u`, etc).
mode?ModeControlled view mode. Omit to let the component manage its own.
defaultMode?ModeInitial view mode when uncontrolled. @default "unified"
onModeChange?(mode: Mode) => voidFires whenever the view mode changes, from a click or the keyboard.
widgets?Record<string, React.ReactNode>Arbitrary React keyed by line address, rendered as a full-width row directly under that line. A line's address is `n<newLineNo>` for any line that exists in the new file (context or addition), or `o<oldLineNo>` for a line that only exists in the old file (a pure deletion) — e.g. `{ "n42": <AiSuggestion />, "o17": <ReviewNote /> }`.
ariaLabel?stringAccessible name for the scrollable diff region.
className?string