Diff View
spectrumui/diff-viewFreeBlock
Proposed file changes with per-file accept and reject.
Install it
npx shadcn@latest add https://ui.spectrumhq.in/r/diff-view.jsonSource
1'use client';23import { useState } from 'react';4import { Check, FileCode2, X } from 'lucide-react';5import { cn } from '@/lib/utils';67const KEYFRAMES = `8@keyframes su-pop { 0% { opacity: 0; transform: scale(0.85) } 100% { opacity: 1; transform: none } }9`;1011export interface DiffLine {12 type: 'context' | 'add' | 'remove';13 text: string;14}1516export interface FileDiff {17 id: string;18 path: string;19 additions: number;20 deletions: number;21 lines: DiffLine[];22}2324export type DiffViewVariant = 'Default' | 'Summary';2526export interface DiffViewProps {27 diffs: FileDiff[];28 onAccept?: (id: string) => void;29 onReject?: (id: string) => void;30 variant?: DiffViewVariant;31 className?: string;32}3334const LINE_STYLES: Record<DiffLine['type'], string> = {35 context: 'text-neutral-500 dark:text-neutral-500',36 add: 'bg-emerald-500/[0.08] text-emerald-800 dark:text-emerald-300',37 remove: 'bg-red-500/[0.07] text-red-700/80 dark:text-red-400/80',38};3940const LINE_SIGNS: Record<DiffLine['type'], string> = { context: ' ', add: '+', remove: '-' };4142export function DiffView({ diffs, onAccept, onReject, variant = 'Default', className }: DiffViewProps) {43 const [decided, setDecided] = useState<Record<string, 'accepted' | 'rejected'>>({});4445 function decide(id: string, decision: 'accepted' | 'rejected') {46 setDecided((previous) => ({ ...previous, [id]: decision }));47 (decision === 'accepted' ? onAccept : onReject)?.(id);48 }4950 return (51 <div className={cn('w-full max-w-[500px] space-y-2.5', className)}>52 <style dangerouslySetInnerHTML={{ __html: KEYFRAMES }} />53 {diffs.map((diff) => {54 const decision = decided[diff.id];55 return (56 <div57 key={diff.id}58 className={cn(59 'overflow-hidden rounded-xl border border-black/[0.07] bg-white transition-opacity duration-200 dark:border-white/[0.08] dark:bg-[#0B0B0D]',60 decision === 'rejected' && 'opacity-45',61 )}62 >63 <div className="flex items-center justify-between gap-3 border-b border-black/[0.06] px-3 py-2 dark:border-white/[0.07]">64 <span className="flex min-w-0 items-center gap-1.5">65 <FileCode2 className="size-3.5 shrink-0 text-neutral-400 dark:text-neutral-500" />66 <span className="truncate font-mono text-[11.5px] font-medium text-neutral-800 dark:text-neutral-200">67 {diff.path}68 </span>69 </span>70// … truncated
What it pulls in
npm packages
Files it writes
More from spectrumui
All 182 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Agent Planagent-plan | spectrumui | Blocks | Free | 1 dep | |
| Agent Stepsagent-steps | spectrumui | Blocks | Free | 1 dep · 2 files | |
| Approval Cardapproval-card | spectrumui | Blocks | Free | 1 dep | |
| Chat Empty Statechat-empty-state | spectrumui | Blocks | Free | 1 dep · 2 files | |
| Citation Sourcescitation-sources | spectrumui | Blocks | Free | no deps · 2 files | |
| Code Blockcode-block | spectrumui | Blocks | Free | 1 dep | |
| Conversation Listconversation-list | spectrumui | Blocks | Free | 1 dep | |
| Error Stateerror-state | spectrumui | Blocks | Free | 1 dep |
