Skip to content

Commit

Permalink
feat: add summary element and fold expansion/folding (fixes #22, #21)
Browse files Browse the repository at this point in the history
  • Loading branch information
Aeolun committed Oct 19, 2023
1 parent a6222c7 commit e47cbe1
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 35 deletions.
23 changes: 21 additions & 2 deletions examples/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ interface ExampleState {
language?: string;
theme: 'dark' | 'light';
enableSyntaxHighlighting?: boolean;
columnHeaders: boolean;
compareMethod?: DiffMethod;
customGutter?: boolean;
}
Expand All @@ -31,6 +32,7 @@ class Example extends Component<{}, ExampleState> {
highlightLine: [],
theme: 'dark',
splitView: true,
columnHeaders: true,
customGutter: true,
enableSyntaxHighlighting: true,
compareMethod: DiffMethod.CHARS
Expand Down Expand Up @@ -145,6 +147,22 @@ class Example extends Component<{}, ExampleState> {
</label>
<span>Syntax highlighting</span>
</div>
<div>
<label className={'switch'}>
<input
type="checkbox"
checked={this.state.columnHeaders}
onChange={() => {
this.setState({
columnHeaders:
!this.state.columnHeaders,
});
}}
/>
<span className="slider round"></span>
</label>
<span>Column Headers</span>
</div>
<div>
<label className={'switch'}>
<input
Expand Down Expand Up @@ -225,8 +243,9 @@ class Example extends Component<{}, ExampleState> {
: undefined
}
useDarkTheme={this.state.theme === 'dark'}
leftTitle={`${this.state.compareMethod === DiffMethod.JSON ? 'package.json' : 'webpack.config.js'} master@2178133 - pushed 2 hours ago.`}
rightTitle={`${this.state.compareMethod === DiffMethod.JSON ? 'package.json' : 'webpack.config.js'} master@64207ee - pushed 13 hours ago.`}
summary={this.state.compareMethod === DiffMethod.JSON ? 'package.json' : 'webpack.config.js'}
leftTitle={this.state.columnHeaders ? `master@2178133 - pushed 2 hours ago.` : undefined}
rightTitle={this.state.columnHeaders ? `master@64207ee - pushed 13 hours ago.` : undefined}
/>
</div>
<footer>
Expand Down
2 changes: 1 addition & 1 deletion src/compute-hidden-blocks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {DiffType, LineInformation} from "./compute-lines";
import {ReactElement} from "react";

interface Block {
export interface Block {
index: number
startLine: number
endLine: number
Expand Down
3 changes: 3 additions & 0 deletions src/expand.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function Expand() {
return <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="m8.177.677 2.896 2.896a.25.25 0 0 1-.177.427H8.75v1.25a.75.75 0 0 1-1.5 0V4H5.104a.25.25 0 0 1-.177-.427L7.823.677a.25.25 0 0 1 .354 0ZM7.25 10.75a.75.75 0 0 1 1.5 0V12h2.146a.25.25 0 0 1 .177.427l-2.896 2.896a.25.25 0 0 1-.354 0l-2.896-2.896A.25.25 0 0 1 5.104 12H7.25v-1.25Zm-5-2a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5ZM6 8a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1 0-1.5h.5A.75.75 0 0 1 6 8Zm2.25.75a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5ZM12 8a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1 0-1.5h.5A.75.75 0 0 1 12 8Zm2.25.75a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5Z"></path></svg>
}
3 changes: 3 additions & 0 deletions src/fold.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function Fold() {
return <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M10.896 2H8.75V.75a.75.75 0 0 0-1.5 0V2H5.104a.25.25 0 0 0-.177.427l2.896 2.896a.25.25 0 0 0 .354 0l2.896-2.896A.25.25 0 0 0 10.896 2ZM8.75 15.25a.75.75 0 0 1-1.5 0V14H5.104a.25.25 0 0 1-.177-.427l2.896-2.896a.25.25 0 0 1 .354 0l2.896 2.896a.25.25 0 0 1-.177.427H8.75v1.25Zm-6.5-6.5a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5ZM6 8a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1 0-1.5h.5A.75.75 0 0 1 6 8Zm2.25.75a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5ZM12 8a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1 0-1.5h.5A.75.75 0 0 1 12 8Zm2.25.75a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5Z"></path></svg>
}
98 changes: 67 additions & 31 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import {ReactElement} from 'react';
import cn from 'classnames';

import {computeLineInformation, DiffInformation, DiffMethod, DiffType, LineInformation,} from './compute-lines';
import computeStyles, {ReactDiffViewerStyles, ReactDiffViewerStylesOverride,} from './styles';
import {ReactElement} from "react";
import {computeHiddenBlocks} from "./compute-hidden-blocks";
import {Block, computeHiddenBlocks} from "./compute-hidden-blocks";
import IntrinsicElements = React.JSX.IntrinsicElements;
import {Expand} from "./expand";
import {Fold} from "./fold";

const m = require('memoize-one');

Expand Down Expand Up @@ -69,6 +70,10 @@ export interface ReactDiffViewerProps {
styles?: ReactDiffViewerStylesOverride;
// Use dark theme.
useDarkTheme?: boolean;
/**
* Used to describe the thing being diffed
*/
summary?: string | ReactElement;
// Title for left column
leftTitle?: string | ReactElement;
// Title for left column
Expand Down Expand Up @@ -519,7 +524,7 @@ class DiffViewer extends React.Component<
/**
* Generates the entire diff view.
*/
private renderDiff = (): {leftLines: ReactElement[], rightLines: ReactElement[]} => {
private renderDiff = (): {leftLines: ReactElement[], rightLines: ReactElement[], lineInformation: LineInformation[], blocks: Block[] } => {
const {
oldValue,
newValue,
Expand Down Expand Up @@ -577,7 +582,7 @@ class DiffViewer extends React.Component<
rightLines.push(...right)
},
);
return {leftLines, rightLines};
return {leftLines, rightLines, lineInformation, blocks};
};

public render = (): ReactElement => {
Expand All @@ -600,36 +605,67 @@ class DiffViewer extends React.Component<

this.styles = this.computeStyles(this.props.styles, useDarkTheme, nonce);
const nodes = this.renderDiff();
const colSpanOnSplitView = hideLineNumbers ? 2 : 3;
const colSpanOnInlineView = hideLineNumbers ? 2 : 4;
let columnExtension = this.props.renderGutter ? 1 : 0;

console.log(nodes.rightLines)
let deletions = 0, additions = 0
nodes.lineInformation.forEach((l) => {
if (l.left.type === DiffType.ADDED) {
additions++
}
if (l.right.type === DiffType.ADDED) {
additions++
}
if (l.left.type === DiffType.REMOVED) {
deletions++
}
if (l.right.type === DiffType.REMOVED) {
deletions++
}
})
const totalChanges = deletions + additions

const percentageAddition = Math.round((additions / totalChanges) * 100)
const blocks: ReactElement[] = []
for(let i = 0; i < 5; i++) {
if (percentageAddition > i * 20) {
blocks.push(<span key={i} className={cn(this.styles.block, this.styles.blockAddition)} />)
} else {
blocks.push(<span key={i} className={cn(this.styles.block, this.styles.blockDeletion)} />)
}
}
const allExpanded = this.state.expandedBlocks.length === nodes.blocks.length

return (
<div
className={cn(this.styles.diffContainer, {
[this.styles.splitView]: splitView,
})}
>
<div className={this.styles.column} role={'table'} title={`Diff information for ${leftTitle}`}>
<div
className={cn(this.styles.titleBlock, this.styles.column)}
role={'columnheader'}
>
<pre className={this.styles.contentText}>{leftTitle}</pre>
</div>
{nodes.leftLines}
<div>
<div className={this.styles.summary} role={'banner'}>
<a style={{ cursor: 'pointer'}} onClick={() => {
this.setState({
expandedBlocks: allExpanded ? [] : nodes.blocks.map(b => b.index)
})
}}>{allExpanded ? <Fold /> : <Expand />}</a> {totalChanges} <div style={{ display: 'flex', gap: '1px'}}>{blocks}</div> {this.props.summary ? <span>{this.props.summary}</span> : null}
</div>
{nodes.rightLines.length > 0 ? <div className={this.styles.column} role={'table'} title={`Diff information for ${rightTitle}`}>
<div
className={cn(this.styles.titleBlock, this.styles.column)}
role={'columnheader'}
>
<pre className={this.styles.contentText}>{rightTitle}</pre>
<div
className={cn(this.styles.diffContainer, {
[this.styles.splitView]: splitView,
})}
>
<div className={this.styles.column} role={'table'} title={`Diff information for ${leftTitle}`}>
{leftTitle ? <div
className={cn(this.styles.titleBlock, this.styles.column)}
role={'columnheader'}
>
<pre className={this.styles.contentText}>{leftTitle}</pre>
</div> : null }
{nodes.leftLines}
</div>
{nodes.rightLines}
</div> : null}
{nodes.rightLines.length > 0 ? <div className={this.styles.column} role={'table'} title={`Diff information for ${rightTitle}`}>
{rightTitle ? <div
className={cn(this.styles.titleBlock, this.styles.column)}
role={'columnheader'}
>
<pre className={this.styles.contentText}>{rightTitle}</pre>
</div> : null}
{nodes.rightLines}
</div> : null}
</div>
</div>
);
};
Expand Down
38 changes: 37 additions & 1 deletion src/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface ReactDiffViewerStyles {
wordAdded?: string;
wordRemoved?: string;
codeFoldGutter?: string;
summary?: string;
codeFoldContentContainer?: string;
emptyGutter?: string;
emptyLine?: string;
Expand Down Expand Up @@ -151,7 +152,7 @@ export default (
removedGutterColor: '#8c8c8c',
codeFoldContentColor: '#656a8b',
diffViewerTitleBackground: '#2f323e',
diffViewerTitleColor: '#555a7b',
diffViewerTitleColor: '#757a9b',
diffViewerTitleBorderColor: '#353846',
},
...(overrideVariables.dark || {}),
Expand All @@ -172,6 +173,17 @@ export default (
label: 'split-view',
});

const summary = css({
background: variables.diffViewerTitleBackground,
color: variables.diffViewerTitleColor,
padding: '0.5em 1em',
display: 'flex',
alignItems: 'center',
gap: '0.5em',
fontFamily: "monospace",
fill: variables.diffViewerTitleColor,
})

const diffContainer = css({
width: '100%',
minWidth: '1000px',
Expand Down Expand Up @@ -261,11 +273,13 @@ export default (

const wordAdded = css({
background: variables.wordAddedBackground,
textDecoration: 'none',
label: 'word-added',
});

const wordRemoved = css({
background: variables.wordRemovedBackground,
textDecoration: 'none',
label: 'word-removed',
});

Expand All @@ -284,6 +298,24 @@ export default (
label: 'code-fold-content',
});

const block = css({
display: 'block',
width: '10px',
height: '10px',
backgroundColor: '#ddd',
borderWidth: '1px',
borderStyle: 'solid',
borderColor: variables.diffViewerTitleBorderColor
});

const blockAddition = css({
backgroundColor: variables.wordAddedBackground
})

const blockDeletion = css({
backgroundColor: variables.wordRemovedBackground
})

const codeFold = css({
backgroundColor: variables.codeFoldBackground,
height: 40,
Expand Down Expand Up @@ -404,6 +436,10 @@ export default (
lineContent,
wordDiff,
wordAdded,
summary,
block,
blockAddition,
blockDeletion,
wordRemoved,
codeFoldGutter,
codeFoldContentContainer,
Expand Down

0 comments on commit e47cbe1

Please sign in to comment.