Skip to content
Merged
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Binary file added apps/docs/app/BerkeleyMonoVariable.woff2
Binary file not shown.
54 changes: 27 additions & 27 deletions apps/docs/app/diff-examples/Annotations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { CornerDownRight } from 'lucide-react';
import { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';

import { FeatureHeader } from './FeatureHeader';

const OLD_FILE: FileContents = {
name: 'file.tsx',
contents: `import * as 'react';
Expand Down Expand Up @@ -45,18 +47,15 @@ export default function Home() {
export function Annotations() {
const [element, setElement] = useState<HTMLElement | undefined>(undefined);
useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
setElement(document.createElement('div'));
}, []);

return (
<div className="space-y-4">
<h3 className="text-2xl font-semibold">Comments & Annotations</h3>
<p className="text-sm text-muted-foreground">
Precision Diffs provides a flexible annotation framework for injecting
additional content and context into your diffs. Use it to render line
comments, annotations from CI jobs, and other third party content.
</p>
<div className="space-y-5">
<FeatureHeader
title="Comments & Annotations"
description="Precision Diffs provides a flexible annotation framework for injecting additional content and context into your diffs. Use it to render line comments, annotations from CI jobs, and other third party content."
/>
{element != null && (
<>
<FileDiff
Expand All @@ -82,35 +81,36 @@ export function Annotations() {

const Thread = () => (
<div
className="max-w-[95%] sm:max-w-[70%]"
style={{
maxWidth: '80%',
whiteSpace: 'normal',
margin: 20,
fontFamily: 'var(--font-body)',
fontFamily: 'Geist',
}}
>
<CommentThread
mainComment={{
author: 'You',
timestamp: '3h',
content:
"What do we think about adding Inter as our primary UI font? It'd definitely help solve some of these layout inconsistencies.",
avatarUrl: '/user-avatar.jpg',
content: 'Good lord, I refuse to look at diffs ever again after this.',
avatarUrl:
'https://db.heypierre.app/storage/v1/object/public/avatars/i8UHRtQf_400x400.jpg',
isYou: true,
}}
replies={[
{
author: 'Ian',
author: 'Amadeus',
timestamp: '2h',
content: 'Oh yeah, love that.',
avatarUrl: '/ian-avatar.jpg',
content: 'Wait, how long have we been working on this?',
avatarUrl:
'https://db.heypierre.app/storage/v1/object/public/avatars/Evzotboe_400x400.jpg',
},
{
author: 'Mark',
timestamp: '2h',
content:
'Oh damn, if we can make it work without a perf hit, yeah totally.',
avatarUrl: '/mark-avatar.jpg',
content: '*checks notes*… it’s not been a short amount of time.',
avatarUrl:
'https://db.heypierre.app/storage/v1/object/public/avatars/BET9cPgr_400x400.jpg',
},
]}
onAddReply={() => console.log('Add reply clicked')}
Expand All @@ -135,8 +135,8 @@ export function Comment({
isYou = false,
}: CommentProps) {
return (
<div className="flex gap-3">
<div className="relative flex-shrink-0">
<div className="flex gap-2">
<div className="relative flex-shrink-0 -mt-0.5">
<Avatar className="h-6 w-6">
<AvatarImage src={avatarUrl ?? '/placeholder.svg'} alt={author} />
<AvatarFallback>{author[0]}</AvatarFallback>
Expand All @@ -149,7 +149,7 @@ export function Comment({
</span>
<span className="text-sm text-muted-foreground">{timestamp}</span>
</div>
<p className="mt-1 text-foreground leading-relaxed">{content}</p>
<p className="text-foreground leading-relaxed">{content}</p>
</div>
</div>
);
Expand All @@ -169,28 +169,28 @@ export function CommentThread({
onResolve,
}: CommentThreadProps) {
return (
<div className="rounded-lg border bg-card p-6 shadow-sm">
<div className="rounded-lg border bg-card p-5 shadow-sm">
<Comment {...mainComment} />

{replies.length > 0 && (
<div className="mt-4 ml-[52px] space-y-4">
<div className="mt-4 ml-8 sm:ml-[32px] space-y-4">
{replies.map((reply, index) => (
<Comment key={index} {...reply} />
))}
</div>
)}

<div className="mt-4 ml-[52px] flex items-center gap-4">
<div className="mt-4 ml-8 sm:ml-[32px] flex items-center gap-4">
<button
onClick={onAddReply}
className="flex items-center gap-1.5 text-sm font-medium text-blue-600 hover:text-blue-700 transition-colors"
className="flex items-center gap-1.5 text-sm text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 transition-colors"
>
<CornerDownRight className="h-4 w-4" />
Add reply...
</button>
<button
onClick={onResolve}
className="text-sm font-medium text-blue-600 hover:text-blue-700 transition-colors"
className="text-sm text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 transition-colors"
>
Resolve
</button>
Expand Down
17 changes: 7 additions & 10 deletions apps/docs/app/diff-examples/ArbitraryFiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import { FileDiff } from '@/components/diff-ui/FileDiff';
import type { FileContents } from '@pierre/diff-ui';

import { FeatureHeader } from './FeatureHeader';

const OLD_FILE: FileContents = {
name: 'file.tsx',
contents: `import * as 'react';
Expand Down Expand Up @@ -40,16 +42,11 @@ export default function Home() {

export function ArbitraryFiles() {
return (
<div className="space-y-4">
<div className="space-y-4">
<h3 className="text-2xl font-semibold">Diff arbitrary files</h3>
<p className="text-sm text-muted-foreground">
In addition to rendering standard Git diffs and patches, you can pass
any two files in Precision Diffs and get a diff between them. This is
especially useful when comparing across generative snapshots where
linear history isn’t always available.
</p>
</div>
<div className="space-y-5">
<FeatureHeader
title="Diff arbitrary files"
description="In addition to rendering standard Git diffs and patches, you can pass any two files in Precision Diffs and get a diff between them. This is especially useful when comparing across generative snapshots where linear history isn't always available."
/>
<FileDiff
oldFile={OLD_FILE}
newFile={NEW_FILE}
Expand Down
194 changes: 141 additions & 53 deletions apps/docs/app/diff-examples/DiffStyles.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
'use client';

import { FileDiff } from '@/components/diff-ui/FileDiff';
import { IconParagraph, IconWordWrap } from '@/components/icons';
import {
IconCheckLg,
IconCodeStyleBars,
IconCodeStyleBg,
IconCodeStyleInline,
IconParagraph,
IconSymbolDiffstat,
IconWordWrap,
} from '@/components/icons';
import { Button } from '@/components/ui/button';
import { ButtonGroup, ButtonGroupItem } from '@/components/ui/button-group';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Switch } from '@/components/ui/switch';
import type { FileContents } from '@pierre/diff-ui';
import { ChevronDown } from 'lucide-react';
import { useState } from 'react';

import { FeatureHeader } from './FeatureHeader';

const OLD_FILE: FileContents = {
name: 'file.tsx',
contents: `import * as 'react';
Expand Down Expand Up @@ -41,6 +60,29 @@ export default function Home() {
`,
};

const diffStyleOptions = [
{
value: 'word-alt',
label: 'Word-Alt',
description: 'Highlight entire words with enhanced algorithm',
},
{
value: 'word',
label: 'Word',
description: 'Highlight changed words within lines',
},
{
value: 'char',
label: 'Character',
description: 'Highlight individual character changes',
},
{
value: 'none',
label: 'None',
description: 'Show line-level changes only',
},
] as const;

export function DiffStyles() {
const [diffIndicators, setDiffStyle] = useState<'classic' | 'bars' | 'none'>(
'bars'
Expand All @@ -52,72 +94,118 @@ export function DiffStyles() {
const [overflow, setOverflow] = useState<'wrap' | 'scroll'>('wrap');

return (
<div className="space-y-4">
<div className="space-y-5">
<div className="space-y-4">
<h3 className="text-2xl font-semibold">
Choose how changes are styled
</h3>
<p className="text-sm text-muted-foreground">
Your diffs, your choice. Render changed lines with classic diff
indicators (+/–), full-width background colors, or vertical bars. You
can even highlight inline changes—character or word based—and toggle
line wrapping, hide numbers, and more.
</p>
<div className="flex flex-col md:flex-row gap-3">
<FeatureHeader
title="Choose how changes are styled"
description="Your diffs, your choice. Render changed lines with classic diff indicators (+/–), full-width background colors, or vertical bars. You can even highlight inline changes—character or word based—and toggle line wrapping, hide numbers, and more."
/>
<div className="flex flex-col sm:flex-row flex-wrap md:items-center gap-3">
<ButtonGroup
value={diffIndicators}
onValueChange={(value) =>
setDiffStyle(value as 'bars' | 'classic' | 'none')
}
>
{['bars', 'classic', 'none'].map((value) => (
<ButtonGroupItem key={value} value={value}>
<ButtonGroupItem
key={value}
value={value}
className="capitalize flex-1"
>
{value === 'bars' ? (
<IconCodeStyleBars />
) : value === 'classic' ? (
<IconSymbolDiffstat />
) : (
<IconParagraph />
)}
{value}
</ButtonGroupItem>
))}
</ButtonGroup>
<ButtonGroup
value={disableBackground ? 'disable' : 'enable'}
onValueChange={(value) => {
if (value === 'disable') {
setDisableBackground(true);
} else {
setDisableBackground(false);

<div className="p-[2px] rounded-lg bg-secondary">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
className="justify-start w-full md:w-auto"
>
<IconCodeStyleInline />
{}
{diffStyleOptions.find((opt) => opt.value === lineDiffStyle)
?.label ?? lineDiffStyle}
<ChevronDown className="text-muted-foreground ml-auto" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-82">
{diffStyleOptions.map((option) => (
<DropdownMenuItem
key={option.value}
onClick={() => setLineDiffStyle(option.value)}
className="flex items-start py-2 gap-2"
>
{lineDiffStyle === option.value ? (
<IconCheckLg className="mt-[1px]" />
) : (
<div className="w-4 h-4" />
)}
<div className="flex flex-col w-full items-start">
<span className="font-medium">{option.label}</span>
<span className="text-xs text-muted-foreground">
{option.description}
</span>
</div>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
</div>

<div className="p-[2px] rounded-lg bg-secondary gridstack">
<Button
variant="outline"
className="justify-between w-full md:w-auto gap-3 pl-3 pr-11"
onClick={() => setDisableBackground(!disableBackground)}
>
<div className="flex items-center gap-2">
<IconCodeStyleBg />
Backgrounds
</div>
</Button>
<Switch
checked={!disableBackground}
onCheckedChange={(checked: boolean) =>
setDisableBackground(!checked)
}
}}
>
{['disable', 'enable'].map((value) => (
<ButtonGroupItem key={value} value={value}>
{value === 'disable' ? 'Disable BG' : 'Enable BG'}
</ButtonGroupItem>
))}
</ButtonGroup>
<ButtonGroup
value={lineDiffStyle}
onValueChange={(value) =>
setLineDiffStyle(value as 'word-alt' | 'word' | 'char' | 'none')
}
>
{['word', 'word-alt', 'char', 'none'].map((value) => (
<ButtonGroupItem key={value} value={value}>
{value}
</ButtonGroupItem>
))}
</ButtonGroup>
onClick={(e) => e.stopPropagation()}
className="justify-self-end place-self-center mr-3 pointer-events-none"
/>
</div>

<ButtonGroup
value={overflow}
onValueChange={(value) => setOverflow(value as 'wrap' | 'scroll')}
>
<ButtonGroupItem value="wrap">
<IconWordWrap />
Wrap
</ButtonGroupItem>
<ButtonGroupItem value="scroll">
<IconParagraph />
No wrap
</ButtonGroupItem>
</ButtonGroup>
<div className="p-[2px] rounded-lg bg-secondary gridstack ">
<Button
variant="outline"
className="justify-between w-full md:w-auto gap-3 pl-3 pr-11"
onClick={() =>
setOverflow(overflow === 'wrap' ? 'scroll' : 'wrap')
}
>
<div className="flex items-center gap-2">
<IconWordWrap />
Wrapping
</div>
</Button>
<Switch
checked={overflow === 'wrap'}
onCheckedChange={(checked: boolean) =>
setOverflow(checked ? 'wrap' : 'scroll')
}
onClick={(e) => e.stopPropagation()}
className="justify-self-end place-self-center mr-3 pointer-events-none"
/>
</div>
</div>
</div>
<FileDiff
Expand Down
Loading