Merge pull request #514 from JHWelch/add-dark-mode

Add Dark & Auto color schemes
This commit is contained in:
Rodrigo Fernandes 2023-09-29 20:13:49 +01:00 committed by GitHub
commit b04a400329
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1290 additions and 108 deletions

View file

@ -201,7 +201,7 @@ diff2htmlUi.draw();
```html
<!-- Stylesheet -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/github.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" />
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css" />
<!-- Javascripts -->
@ -227,6 +227,21 @@ document.addEventListener('DOMContentLoaded', () => {
});
```
When using the `auto` color scheme, you will need to specify both the light and dark themes for highlight.js to use.
```html
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css"
media="screen and (prefers-color-scheme: light)"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github-dark.min.css"
media="screen and (prefers-color-scheme: dark)"
/>
```
#### Collapsable File Summary List
> Add the dependencies.
@ -386,6 +401,8 @@ The HTML output accepts a Javascript object with configuration. Possible options
> [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)
- `highlightLanguages`: Map of extension to language name, used for highlighting. This overrides the default language
detection based on file extensions.
- `colorScheme`: color scheme to use for the diff, default is `light`. Possible values are `light`, `dark`, and `auto`
which will use the browser's preferred color scheme.
### Diff2Html Browser

View file

@ -1,7 +1,7 @@
import fs from 'fs';
import { parse, html } from '../diff2html';
import { DiffFile, LineType, OutputFormatType } from '../types';
import { ColorSchemeType, DiffFile, LineType, OutputFormatType } from '../types';
const diffExample1 =
'diff --git a/sample b/sample\n' +
@ -205,7 +205,7 @@ describe('Diff2Html', () => {
it('should generate pretty line by line html from diff', () => {
const result = html(diffExample1, { drawFileList: false });
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-wrapper">
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -262,7 +262,7 @@ describe('Diff2Html', () => {
it('should generate pretty line by line html from json', () => {
const result = html(jsonExample1, { drawFileList: false });
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-wrapper">
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -319,7 +319,7 @@ describe('Diff2Html', () => {
it('should generate pretty diff with files summary', () => {
const result = html(diffExample1, { drawFileList: true });
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-file-list-wrapper">
"<div class="d2h-file-list-wrapper d2h-light-color-scheme">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed (1)</span>
<a class="d2h-file-switch d2h-hide">hide</a>
@ -339,7 +339,7 @@ describe('Diff2Html', () => {
</span>
</li>
</ol>
</div><div class="d2h-wrapper">
</div><div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -396,7 +396,7 @@ describe('Diff2Html', () => {
it('should generate pretty side by side html from diff', () => {
const result = html(diffExample1, { outputFormat: OutputFormatType.SIDE_BY_SIDE, drawFileList: false });
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-wrapper">
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -467,7 +467,7 @@ describe('Diff2Html', () => {
it('should generate pretty side by side html from json', () => {
const result = html(jsonExample1, { outputFormat: OutputFormatType.SIDE_BY_SIDE, drawFileList: false });
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-wrapper">
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -538,7 +538,7 @@ describe('Diff2Html', () => {
it('should generate pretty side by side html from diff 2', () => {
const result = html(diffExample1, { outputFormat: OutputFormatType.SIDE_BY_SIDE, drawFileList: true });
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-file-list-wrapper">
"<div class="d2h-file-list-wrapper d2h-light-color-scheme">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed (1)</span>
<a class="d2h-file-switch d2h-hide">hide</a>
@ -558,7 +558,7 @@ describe('Diff2Html', () => {
</span>
</li>
</ol>
</div><div class="d2h-wrapper">
</div><div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -652,7 +652,7 @@ describe('Diff2Html', () => {
' \n';
const result = html(diffExample2, { drawFileList: false });
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-wrapper">
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-211439" class="d2h-file-wrapper" data-lang="md">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -878,7 +878,7 @@ describe('Diff2Html', () => {
const result = html(diff);
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-file-list-wrapper">
"<div class="d2h-file-list-wrapper d2h-light-color-scheme">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed (1)</span>
<a class="d2h-file-switch d2h-hide">hide</a>
@ -898,7 +898,7 @@ describe('Diff2Html', () => {
</span>
</li>
</ol>
</div><div class="d2h-wrapper">
</div><div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-597266" class="d2h-file-wrapper" data-lang="html">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -980,7 +980,7 @@ describe('Diff2Html', () => {
const result = html(diff);
/* eslint-disable no-irregular-whitespace */
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-file-list-wrapper">
"<div class="d2h-file-list-wrapper d2h-light-color-scheme">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed (1)</span>
<a class="d2h-file-switch d2h-hide">hide</a>
@ -1000,7 +1000,7 @@ describe('Diff2Html', () => {
</span>
</li>
</ol>
</div><div class="d2h-wrapper">
</div><div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-719103" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -1258,5 +1258,289 @@ describe('Diff2Html', () => {
`);
/* eslint-enable no-irregular-whitespace */
});
describe('with auto colorScheme', () => {
it('should return a html diff with auto color scheme', () => {
const result = html(diffExample1, {
drawFileList: false,
colorScheme: ColorSchemeType.AUTO,
});
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-wrapper d2h-auto-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">sample</span>
<span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class="d2h-file-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<tr>
<td class="d2h-code-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-line">@@ -1 +1 @@</div>
</td>
</tr><tr>
<td class="d2h-code-linenumber d2h-del d2h-change">
<div class="line-num1">1</div>
<div class="line-num2"></div>
</td>
<td class="d2h-del d2h-change">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">-</span>
<span class="d2h-code-line-ctn"><del>test</del></span>
</div>
</td>
</tr><tr>
<td class="d2h-code-linenumber d2h-ins d2h-change">
<div class="line-num1"></div>
<div class="line-num2">1</div>
</td>
<td class="d2h-ins d2h-change">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn"><ins>test1</ins></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>"
`);
});
it('should include auto colorScheme on file list', () => {
const result = html(diffExample1, {
drawFileList: true,
colorScheme: ColorSchemeType.AUTO,
});
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-file-list-wrapper d2h-auto-color-scheme">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed (1)</span>
<a class="d2h-file-switch d2h-hide">hide</a>
<a class="d2h-file-switch d2h-show">show</a>
</div>
<ol class="d2h-file-list">
<li class="d2h-file-list-line">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon d2h-changed" height="16" title="modified" version="1.1"
viewBox="0 0 14 16" width="14">
<path d="M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM4 8c0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3-3-1.34-3-3z"></path>
</svg> <a href="#d2h-675094" class="d2h-file-name">sample</a>
<span class="d2h-file-stats">
<span class="d2h-lines-added">+1</span>
<span class="d2h-lines-deleted">-1</span>
</span>
</span>
</li>
</ol>
</div><div class="d2h-wrapper d2h-auto-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">sample</span>
<span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class="d2h-file-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<tr>
<td class="d2h-code-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-line">@@ -1 +1 @@</div>
</td>
</tr><tr>
<td class="d2h-code-linenumber d2h-del d2h-change">
<div class="line-num1">1</div>
<div class="line-num2"></div>
</td>
<td class="d2h-del d2h-change">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">-</span>
<span class="d2h-code-line-ctn"><del>test</del></span>
</div>
</td>
</tr><tr>
<td class="d2h-code-linenumber d2h-ins d2h-change">
<div class="line-num1"></div>
<div class="line-num2">1</div>
</td>
<td class="d2h-ins d2h-change">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn"><ins>test1</ins></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>"
`);
});
});
describe('with dark colorScheme', () => {
it('should return a html diff with dark mode', () => {
const result = html(diffExample1, {
drawFileList: false,
colorScheme: ColorSchemeType.DARK,
});
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-wrapper d2h-dark-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">sample</span>
<span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class="d2h-file-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<tr>
<td class="d2h-code-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-line">@@ -1 +1 @@</div>
</td>
</tr><tr>
<td class="d2h-code-linenumber d2h-del d2h-change">
<div class="line-num1">1</div>
<div class="line-num2"></div>
</td>
<td class="d2h-del d2h-change">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">-</span>
<span class="d2h-code-line-ctn"><del>test</del></span>
</div>
</td>
</tr><tr>
<td class="d2h-code-linenumber d2h-ins d2h-change">
<div class="line-num1"></div>
<div class="line-num2">1</div>
</td>
<td class="d2h-ins d2h-change">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn"><ins>test1</ins></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>"
`);
});
it('should include dark colorScheme on file list', () => {
const result = html(diffExample1, {
drawFileList: true,
colorScheme: ColorSchemeType.DARK,
});
expect(result).toMatchInlineSnapshot(`
"<div class="d2h-file-list-wrapper d2h-dark-color-scheme">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed (1)</span>
<a class="d2h-file-switch d2h-hide">hide</a>
<a class="d2h-file-switch d2h-show">show</a>
</div>
<ol class="d2h-file-list">
<li class="d2h-file-list-line">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon d2h-changed" height="16" title="modified" version="1.1"
viewBox="0 0 14 16" width="14">
<path d="M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM4 8c0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3-3-1.34-3-3z"></path>
</svg> <a href="#d2h-675094" class="d2h-file-name">sample</a>
<span class="d2h-file-stats">
<span class="d2h-lines-added">+1</span>
<span class="d2h-lines-deleted">-1</span>
</span>
</span>
</li>
</ol>
</div><div class="d2h-wrapper d2h-dark-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">sample</span>
<span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class="d2h-file-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<tr>
<td class="d2h-code-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-line">@@ -1 +1 @@</div>
</td>
</tr><tr>
<td class="d2h-code-linenumber d2h-del d2h-change">
<div class="line-num1">1</div>
<div class="line-num2"></div>
</td>
<td class="d2h-del d2h-change">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">-</span>
<span class="d2h-code-line-ctn"><del>test</del></span>
</div>
</td>
</tr><tr>
<td class="d2h-code-linenumber d2h-ins d2h-change">
<div class="line-num1"></div>
<div class="line-num2">1</div>
</td>
<td class="d2h-ins d2h-change">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn"><ins>test1</ins></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>"
`);
});
});
});
});

View file

@ -1,8 +1,9 @@
import { render } from '../file-list-renderer';
import { FileListRenderer } from '../file-list-renderer';
import HoganJsUtils from '../hoganjs-utils';
import { ColorSchemeType } from '../types';
describe('FileListPrinter', () => {
describe('generateFileList', () => {
describe('FileListRenderer', () => {
describe('render', () => {
it('should expose old and new files to templates', () => {
const hoganUtils = new HoganJsUtils({
rawTemplates: {
@ -10,6 +11,7 @@ describe('FileListPrinter', () => {
'file-summary-line': '{{oldName}}, {{newName}}, {{fileName}}',
},
});
const fileListRenderer = new FileListRenderer(hoganUtils);
const files = [
{
isCombined: false,
@ -55,7 +57,7 @@ describe('FileListPrinter', () => {
},
];
const fileHtml = render(files, hoganUtils);
const fileHtml = fileListRenderer.render(files);
expect(fileHtml).toMatchInlineSnapshot(`
"my/file/name.js, my/file/name.js, my/file/name.js
@ -67,6 +69,8 @@ describe('FileListPrinter', () => {
it('should work for all kinds of files', () => {
const hoganUtils = new HoganJsUtils({});
const fileListRenderer = new FileListRenderer(hoganUtils);
const files = [
{
isCombined: false,
@ -111,9 +115,9 @@ describe('FileListPrinter', () => {
isDeleted: true,
},
];
const fileHtml = render(files, hoganUtils);
const fileHtml = fileListRenderer.render(files);
expect(fileHtml).toMatchInlineSnapshot(`
"<div class="d2h-file-list-wrapper">
"<div class="d2h-file-list-wrapper d2h-light-color-scheme">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed (4)</span>
<a class="d2h-file-switch d2h-hide">hide</a>
@ -172,5 +176,97 @@ describe('FileListPrinter', () => {
</div>"
`);
});
describe('with dark colorScheme', () => {
it('should include dark colorScheme', () => {
const hoganUtils = new HoganJsUtils({});
const fileListRenderer = new FileListRenderer(hoganUtils, {
colorScheme: ColorSchemeType.DARK,
});
const files = [
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
},
];
const fileHtml = fileListRenderer.render(files);
expect(fileHtml).toMatchInlineSnapshot(`
"<div class="d2h-file-list-wrapper d2h-dark-color-scheme">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed (1)</span>
<a class="d2h-file-switch d2h-hide">hide</a>
<a class="d2h-file-switch d2h-show">show</a>
</div>
<ol class="d2h-file-list">
<li class="d2h-file-list-line">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon d2h-changed" height="16" title="modified" version="1.1"
viewBox="0 0 14 16" width="14">
<path d="M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM4 8c0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3-3-1.34-3-3z"></path>
</svg> <a href="#d2h-781444" class="d2h-file-name">my/file/name.js</a>
<span class="d2h-file-stats">
<span class="d2h-lines-added">+12</span>
<span class="d2h-lines-deleted">-41</span>
</span>
</span>
</li>
</ol>
</div>"
`);
});
});
describe('with auto colorScheme', () => {
it('should include auto colorScheme', () => {
const hoganUtils = new HoganJsUtils({});
const fileListRenderer = new FileListRenderer(hoganUtils, {
colorScheme: ColorSchemeType.AUTO,
});
const files = [
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
},
];
const fileHtml = fileListRenderer.render(files);
expect(fileHtml).toMatchInlineSnapshot(`
"<div class="d2h-file-list-wrapper d2h-auto-color-scheme">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed (1)</span>
<a class="d2h-file-switch d2h-hide">hide</a>
<a class="d2h-file-switch d2h-show">show</a>
</div>
<ol class="d2h-file-list">
<li class="d2h-file-list-line">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon d2h-changed" height="16" title="modified" version="1.1"
viewBox="0 0 14 16" width="14">
<path d="M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM4 8c0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3-3-1.34-3-3z"></path>
</svg> <a href="#d2h-781444" class="d2h-file-name">my/file/name.js</a>
<span class="d2h-file-stats">
<span class="d2h-lines-added">+12</span>
<span class="d2h-lines-deleted">-41</span>
</span>
</span>
</li>
</ol>
</div>"
`);
});
});
});
});

View file

@ -449,7 +449,7 @@ describe('LineByLineRenderer', () => {
});
const html = lineByLineRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(`
"<div class="d2h-wrapper">
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="txt">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -523,7 +523,7 @@ describe('LineByLineRenderer', () => {
});
const html = lineByLineRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(`
"<div class="d2h-wrapper">
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -583,7 +583,7 @@ describe('LineByLineRenderer', () => {
const lineByLineRenderer = new LineByLineRenderer(hoganUtils);
const html = lineByLineRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(`
"<div class="d2h-wrapper">
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">

View file

@ -278,7 +278,7 @@ describe('SideBySideRenderer', () => {
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, { matching: LineMatchingType.LINES });
const html = sideBySideRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(`
"<div class="d2h-wrapper">
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="txt">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -363,7 +363,7 @@ describe('SideBySideRenderer', () => {
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, {});
const html = sideBySideRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(`
"<div class="d2h-wrapper">
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
@ -434,7 +434,7 @@ describe('SideBySideRenderer', () => {
const sideBySideRenderer = new SideBySideRenderer(hoganUtils);
const html = sideBySideRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(`
"<div class="d2h-wrapper">
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">

View file

@ -1,5 +1,5 @@
import * as DiffParser from './diff-parser';
import * as fileListPrinter from './file-list-renderer';
import { FileListRenderer } from './file-list-renderer';
import LineByLineRenderer, { LineByLineRendererConfig, defaultLineByLineRendererConfig } from './line-by-line-renderer';
import SideBySideRenderer, { SideBySideRendererConfig, defaultSideBySideRendererConfig } from './side-by-side-renderer';
import { DiffFile, OutputFormatType } from './types';
@ -32,7 +32,10 @@ export function html(diffInput: string | DiffFile[], configuration: Diff2HtmlCon
const hoganUtils = new HoganJsUtils(config);
const fileList = config.drawFileList ? fileListPrinter.render(diffJson, hoganUtils) : '';
const { colorScheme } = config;
const fileListRendererConfig = { colorScheme };
const fileList = config.drawFileList ? new FileListRenderer(hoganUtils, fileListRendererConfig).render(diffJson) : '';
const diffOutput =
config.outputFormat === 'side-by-side'

View file

@ -1,33 +1,52 @@
import * as renderUtils from './render-utils';
import HoganJsUtils from './hoganjs-utils';
import { DiffFile } from './types';
import { ColorSchemeType, DiffFile } from './types';
const baseTemplatesPath = 'file-summary';
const iconsBaseTemplatesPath = 'icon';
export function render(diffFiles: DiffFile[], hoganUtils: HoganJsUtils): string {
const files = diffFiles
.map(file =>
hoganUtils.render(
baseTemplatesPath,
'line',
{
fileHtmlId: renderUtils.getHtmlId(file),
oldName: file.oldName,
newName: file.newName,
fileName: renderUtils.filenameDiff(file),
deletedLines: '-' + file.deletedLines,
addedLines: '+' + file.addedLines,
},
{
fileIcon: hoganUtils.template(iconsBaseTemplatesPath, renderUtils.getFileIcon(file)),
},
),
)
.join('\n');
return hoganUtils.render(baseTemplatesPath, 'wrapper', {
filesNumber: diffFiles.length,
files: files,
});
export interface FileListRendererConfig {
colorScheme?: ColorSchemeType;
}
export const defaultFileListRendererConfig = {
colorScheme: renderUtils.defaultRenderConfig.colorScheme,
};
export class FileListRenderer {
private readonly hoganUtils: HoganJsUtils;
private readonly config: typeof defaultFileListRendererConfig;
constructor(hoganUtils: HoganJsUtils, config: FileListRendererConfig = {}) {
this.hoganUtils = hoganUtils;
this.config = { ...defaultFileListRendererConfig, ...config };
}
render(diffFiles: DiffFile[]): string {
const files = diffFiles
.map(file =>
this.hoganUtils.render(
baseTemplatesPath,
'line',
{
fileHtmlId: renderUtils.getHtmlId(file),
oldName: file.oldName,
newName: file.newName,
fileName: renderUtils.filenameDiff(file),
deletedLines: '-' + file.deletedLines,
addedLines: '+' + file.addedLines,
},
{
fileIcon: this.hoganUtils.template(iconsBaseTemplatesPath, renderUtils.getFileIcon(file)),
},
),
)
.join('\n');
return this.hoganUtils.render(baseTemplatesPath, 'wrapper', {
colorScheme: renderUtils.colorSchemeToCss(this.config.colorScheme),
filesNumber: diffFiles.length,
files: files,
});
}
}

View file

@ -52,7 +52,10 @@ export default class LineByLineRenderer {
})
.join('\n');
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', { content: diffsHtml });
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', {
colorScheme: renderUtils.colorSchemeToCss(this.config.colorScheme),
content: diffsHtml,
});
}
makeFileDiffHtml(file: DiffFile, diffs: string): string {

View file

@ -2,7 +2,15 @@ import * as jsDiff from 'diff';
import { unifyPath, hashCode } from './utils';
import * as rematch from './rematch';
import { LineMatchingType, DiffStyleType, LineType, DiffLineParts, DiffFile, DiffFileName } from './types';
import {
ColorSchemeType,
DiffFile,
DiffFileName,
DiffLineParts,
DiffStyleType,
LineMatchingType,
LineType,
} from './types';
export type CSSLineClass =
| 'd2h-ins'
@ -37,6 +45,7 @@ export interface RenderConfig {
matchWordsThreshold?: number;
maxLineLengthHighlight?: number;
diffStyle?: DiffStyleType;
colorScheme?: ColorSchemeType;
}
export const defaultRenderConfig = {
@ -44,6 +53,7 @@ export const defaultRenderConfig = {
matchWordsThreshold: 0.25,
maxLineLengthHighlight: 10000,
diffStyle: DiffStyleType.WORD,
colorScheme: ColorSchemeType.LIGHT,
};
const separator = '/';
@ -76,6 +86,18 @@ export function toCSSClass(lineType: LineType): CSSLineClass {
}
}
export function colorSchemeToCss(colorScheme: ColorSchemeType): string {
switch (colorScheme) {
case ColorSchemeType.DARK:
return 'd2h-dark-color-scheme';
case ColorSchemeType.AUTO:
return 'd2h-auto-color-scheme';
case ColorSchemeType.LIGHT:
default:
return 'd2h-light-color-scheme';
}
}
/**
* Prefix length of the hunk lines in the diff
*/

View file

@ -52,7 +52,10 @@ export default class SideBySideRenderer {
})
.join('\n');
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', { content: diffsHtml });
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', {
colorScheme: renderUtils.colorSchemeToCss(this.config.colorScheme),
content: diffsHtml,
});
}
makeFileDiffHtml(file: DiffFile, diffs: FileHtml): string {

View file

@ -1,4 +1,4 @@
<div class="d2h-file-list-wrapper">
<div class="d2h-file-list-wrapper {{colorScheme}}">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed ({{filesNumber}})</span>
<a class="d2h-file-switch d2h-hide">hide</a>

View file

@ -1,3 +1,3 @@
<div class="d2h-wrapper">
<div class="d2h-wrapper {{colorScheme}}">
{{{content}}}
</div>

View file

@ -91,3 +91,9 @@ export const DiffStyleType: { [_: string]: DiffStyleType } = {
WORD: 'word',
CHAR: 'char',
};
export enum ColorSchemeType {
AUTO = 'auto',
DARK = 'dark',
LIGHT = 'light',
}

View file

@ -5,6 +5,81 @@
*
*/
:root {
--d2h-bg-color: #fff;
--d2h-border-color: #ddd;
--d2h-dim-color: rgba(0, 0, 0, 0.3);
--d2h-line-border-color: #eeeeee;
--d2h-file-header-bg-color: #f7f7f7;
--d2h-file-header-border-color: #d8d8d8;
--d2h-empty-placeholder-bg-color: #f1f1f1;
--d2h-empty-placeholder-border-color: #e1e1e1;
--d2h-selected-color: #c8e1ff;
--d2h-ins-bg-color: #dfd;
--d2h-ins-border-color: #b4e2b4;
--d2h-ins-highlight-bg-color: #97f295;
--d2h-ins-label-color: #399839;
--d2h-del-bg-color: #fee8e9;
--d2h-del-border-color: #e9aeae;
--d2h-del-highlight-bg-color: #ffb6ba;
--d2h-del-label-color: #c33;
--d2h-change-del-color: #fdf2d0;
--d2h-change-ins-color: #ded;
--d2h-info-bg-color: #f8fafd;
--d2h-info-border-color: #d5e4f2;
--d2h-change-label-color: #d0b44c;
--d2h-moved-label-color: #3572b0;
/**
* Dark Color Scheme
*/
--d2h-dark-color: rgb(230, 237, 243);
--d2h-dark-bg-color: rgb(13, 17, 23);
--d2h-dark-border-color: rgb(48, 54, 61);
--d2h-dark-dim-color: rgb(110, 118, 129);
--d2h-dark-line-border-color: rgb(33, 38, 45);
--d2h-dark-file-header-bg-color: rgb(22, 27, 34);
--d2h-dark-file-header-border-color: rgb(48, 54, 61);
--d2h-dark-empty-placeholder-bg-color: #rgba(110, 118, 129, 0.1);
--d2h-dark-empty-placeholder-border-color: rgb(48, 54, 61);
--d2h-dark-selected-color: rgba(56, 139, 253, 0.1);
--d2h-dark-ins-bg-color: rgba(46, 160, 67, 0.15);
--d2h-dark-ins-border-color: rgba(46, 160, 67, 0.4);
--d2h-dark-ins-highlight-bg-color: rgba(46, 160, 67, 0.4);
--d2h-dark-ins-label-color: rgb(63, 185, 80);
--d2h-dark-del-bg-color: rgba(248, 81, 73, 0.1);
--d2h-dark-del-border-color: rgba(248, 81, 73, 0.4);
--d2h-dark-del-highlight-bg-color: rgba(248, 81, 73, 0.4);
--d2h-dark-del-label-color: rgb(248, 81, 73);
--d2h-dark-change-del-color: rgba(210, 153, 34, 0.2);
--d2h-dark-change-ins-color: rgba(46, 160, 67, 0.25);
--d2h-dark-info-bg-color: rgba(56, 139, 253, 0.1);
--d2h-dark-info-border-color: rgba(56, 139, 253, 0.4);
--d2h-dark-change-label-color: rgb(210, 153, 34);
--d2h-dark-moved-label-color: #3572b0;
}
.d2h-wrapper {
text-align: left;
}
@ -13,10 +88,11 @@
display: flex;
height: 35px;
padding: 5px 10px;
border-bottom: 1px solid #d8d8d8;
background-color: #f7f7f7;
border-bottom: 1px solid var(--d2h-file-header-border-color);
background-color: var(--d2h-file-header-bg-color);
font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.d2h-file-header.d2h-sticky-header {
position: sticky;
top: 0;
@ -33,18 +109,18 @@
.d2h-lines-added {
text-align: right;
border: 1px solid #b4e2b4;
border: 1px solid var(--d2h-ins-border-color);
border-radius: 5px 0 0 5px;
color: #399839;
color: var(--d2h-ins-label-color);
padding: 2px;
vertical-align: middle;
}
.d2h-lines-deleted {
text-align: left;
border: 1px solid #e9aeae;
border: 1px solid var(--d2h-del-border-color);
border-radius: 0 5px 5px 0;
color: #c33;
color: var(--d2h-del-label-color);
padding: 2px;
vertical-align: middle;
margin-left: 1px;
@ -68,7 +144,7 @@
}
.d2h-file-wrapper {
border: 1px solid #ddd;
border: 1px solid var(--d2h-border-color);
border-radius: 3px;
margin-bottom: 1em;
}
@ -80,12 +156,12 @@
font-size: 12px;
align-items: center;
border-radius: 3px;
border: 1px solid #ddd;
border: 1px solid var(--d2h-border-color);
padding: 4px 8px;
}
.d2h-file-collapse.d2h-selected {
background-color: #c8e1ff;
background-color: var(--d2h-selected-color);
}
.d2h-file-collapse-input {
@ -154,7 +230,7 @@
display: inline-block;
margin-top: -1px;
text-decoration: none;
background-color: #ffb6ba;
background-color: var(--d2h-del-highlight-bg-color);
border-radius: 0.2em;
}
@ -163,7 +239,7 @@
display: inline-block;
margin-top: -1px;
text-decoration: none;
background-color: #97f295;
background-color: var(--d2h-ins-highlight-bg-color);
border-radius: 0.2em;
text-align: left;
}
@ -200,10 +276,10 @@
/* Keep the numbers fixed on line contents scroll */
position: absolute;
display: inline-block;
background-color: #fff;
color: rgba(0, 0, 0, 0.3);
background-color: var(--d2h-bg-color);
color: var(--d2h-dim-color);
text-align: right;
border: solid #eeeeee;
border: solid var(--d2h-line-border-color);
border-width: 0 1px 0 1px;
cursor: pointer;
}
@ -218,10 +294,10 @@
display: inline-block;
box-sizing: border-box;
width: 4em;
background-color: #fff;
color: rgba(0, 0, 0, 0.3);
background-color: var(--d2h-bg-color);
color: var(--d2h-dim-color);
text-align: right;
border: solid #eeeeee;
border: solid var(--d2h-line-border-color);
border-width: 0 1px 0 1px;
cursor: pointer;
overflow: hidden;
@ -235,8 +311,8 @@
.d2h-code-side-emptyplaceholder,
.d2h-emptyplaceholder {
background-color: #f1f1f1;
border-color: #e1e1e1;
background-color: var(--d2h-empty-placeholder-bg-color);
border-color: var(--d2h-empty-placeholder-border-color);
}
.d2h-code-linenumber,
@ -256,27 +332,27 @@
*/
.d2h-del {
background-color: #fee8e9;
border-color: #e9aeae;
background-color: var(--d2h-del-bg-color);
border-color: var(--d2h-del-border-color);
}
.d2h-ins {
background-color: #dfd;
border-color: #b4e2b4;
background-color: var(--d2h-ins-bg-color);
border-color: var(--d2h-ins-border-color);
}
.d2h-info {
background-color: #f8fafd;
color: rgba(0, 0, 0, 0.3);
border-color: #d5e4f2;
background-color: var(--d2h-info-bg-color);
color: var(--d2h-dim-color);
border-color: var(--d2h-info-border-color);
}
.d2h-file-diff .d2h-del.d2h-change {
background-color: #fdf2d0;
background-color: var(--d2h-change-del-color);
}
.d2h-file-diff .d2h-ins.d2h-change {
background-color: #ded;
background-color: var(--d2h-change-ins-color);
}
/*
@ -289,11 +365,11 @@
.d2h-file-list-wrapper a {
text-decoration: none;
color: #3572b0;
color: var(--d2h-moved-label-color);
}
.d2h-file-list-wrapper a:visited {
color: #3572b0;
color: var(--d2h-moved-label-color);
}
.d2h-file-list-header {
@ -319,7 +395,7 @@
}
.d2h-file-list > li {
border-bottom: #ddd solid 1px;
border-bottom: var(--d2h-border-color) solid 1px;
padding: 5px 10px;
margin: 0;
}
@ -341,19 +417,19 @@
}
.d2h-deleted {
color: #c33;
color: var(--d2h-del-label-color);
}
.d2h-added {
color: #399839;
color: var(--d2h-ins-label-color);
}
.d2h-changed {
color: #d0b44c;
color: var(--d2h-change-label-color);
}
.d2h-moved {
color: #3572b0;
color: var(--d2h-moved-label-color);
}
.d2h-tag {
@ -363,21 +439,302 @@
font-size: 10px;
margin-left: 5px;
padding: 0 2px;
background-color: #fff;
background-color: var(--d2h-bg-color);
}
.d2h-deleted-tag {
border: #c33 1px solid;
border: var(--d2h-del-label-color) 1px solid;
}
.d2h-added-tag {
border: #399839 1px solid;
border: var(--d2h-ins-label-color) 1px solid;
}
.d2h-changed-tag {
border: #d0b44c 1px solid;
border: var(--d2h-change-label-color) 1px solid;
}
.d2h-moved-tag {
border: #3572b0 1px solid;
border: var(--d2h-moved-label-color) 1px solid;
}
/**
* Dark Mode Colors
*/
.d2h-dark-color-scheme {
color: var(--d2h-dark-color);
background-color: var(--d2h-dark-bg-color);
}
.d2h-dark-color-scheme .d2h-file-header {
background-color: var(--d2h-dark-file-header-bg-color);
border-bottom: var(--d2h-dark-file-header-border-color);
}
.d2h-dark-color-scheme .d2h-lines-added {
border: 1px solid var(--d2h-dark-ins-border-color);
color: var(--d2h-dark-ins-label-color);
}
.d2h-dark-color-scheme .d2h-lines-deleted {
border: 1px solid var(--d2h-dark-del-border-color);
color: var(--d2h-dark-del-label-color);
}
.d2h-dark-color-scheme .d2h-code-line del,
.d2h-dark-color-scheme .d2h-code-side-line del {
background-color: var(--d2h-dark-del-highlight-bg-color);
}
.d2h-dark-color-scheme .d2h-code-line ins,
.d2h-dark-color-scheme .d2h-code-side-line ins {
background-color: var(--d2h-dark-ins-highlight-bg-color);
}
.d2h-dark-color-scheme .d2h-diff-tbody {
border-color: var(--d2h-dark-border-color);
}
.d2h-dark-color-scheme .d2h-code-side-linenumber {
background-color: var(--d2h-dark-bg-color);
color: var(--d2h-dark-dim-color);
border-color: var(--d2h-dark-line-border-color);
}
.d2h-dark-color-scheme .d2h-files-diff .d2h-code-side-emptyplaceholder,
.d2h-dark-color-scheme .d2h-files-diff .d2h-emptyplaceholder {
background-color: var(--d2h-dark-empty-placeholder-bg-color);
border-color: var(--d2h-dark-empty-placeholder-border-color);
}
.d2h-dark-color-scheme .d2h-code-linenumber {
background-color: var(--d2h-dark-bg-color);
color: var(--d2h-dark-dim-color);
border-color: var(--d2h-dark-line-border-color);
}
.d2h-dark-color-scheme .d2h-del {
background-color: var(--d2h-dark-del-bg-color);
border-color: var(--d2h-dark-del-border-color);
}
.d2h-dark-color-scheme .d2h-ins {
background-color: var(--d2h-dark-ins-bg-color);
border-color: var(--d2h-dark-ins-border-color);
}
.d2h-dark-color-scheme .d2h-info {
background-color: var(--d2h-dark-info-bg-color);
color: var(--d2h-dark-dim-color);
border-color: var(--d2h-dark-info-border-color);
}
.d2h-dark-color-scheme .d2h-file-diff .d2h-del.d2h-change {
background-color: var(--d2h-dark-change-del-color);
}
.d2h-dark-color-scheme .d2h-file-diff .d2h-ins.d2h-change {
background-color: var(--d2h-dark-change-ins-color);
}
.d2h-dark-color-scheme .d2h-file-wrapper {
border: 1px solid var(--d2h-dark-border-color);
}
.d2h-dark-color-scheme .d2h-file-collapse {
border: 1px solid var(--d2h-dark-bg-color);
}
.d2h-dark-color-scheme .d2h-file-collapse.d2h-selected {
background-color: var(--d2h-dark-selected-color);
}
.d2h-dark-color-scheme .d2h-file-list-wrapper a {
color: var(--d2h-dark-moved-label-color);
}
.d2h-dark-color-scheme .d2h-file-list-wrapper a:visited {
color: var(--d2h-dark-moved-label-color);
}
.d2h-dark-color-scheme .d2h-file-list > li {
border-bottom: var(--d2h-dark-bg-color) solid 1px;
}
.d2h-dark-color-scheme .d2h-deleted {
color: var(--d2h-dark-del-label-color);
}
.d2h-dark-color-scheme .d2h-added {
color: var(--d2h-dark-ins-label-color);
}
.d2h-dark-color-scheme .d2h-changed {
color: var(--d2h-dark-change-label-color);
}
.d2h-dark-color-scheme .d2h-moved {
color: var(--d2h-dark-moved-label-color);
}
.d2h-dark-color-scheme .d2h-tag {
background-color: var(--d2h-dark-bg-color);
}
.d2h-dark-color-scheme .d2h-deleted-tag {
border: var(--d2h-dark-del-label-color) 1px solid;
}
.d2h-dark-color-scheme .d2h-added-tag {
border: var(--d2h-dark-ins-label-color) 1px solid;
}
.d2h-dark-color-scheme .d2h-changed-tag {
border: var(--d2h-dark-change-label-color) 1px solid;
}
.d2h-dark-color-scheme .d2h-moved-tag {
border: var(--d2h-dark-moved-label-color) 1px solid;
}
/**
* Auto Mode Colors
*/
@media (prefers-color-scheme: dark) {
.d2h-auto-color-scheme {
background-color: var(--d2h-dark-bg-color);
color: var(--d2h-dark-color);
}
.d2h-auto-color-scheme .d2h-file-header {
background-color: var(--d2h-dark-file-header-bg-color);
border-bottom: var(--d2h-dark-file-header-border-color);
}
.d2h-auto-color-scheme .d2h-lines-added {
border: 1px solid var(--d2h-dark-ins-border-color);
color: var(--d2h-dark-ins-label-color);
}
.d2h-auto-color-scheme .d2h-lines-deleted {
border: 1px solid var(--d2h-dark-del-border-color);
color: var(--d2h-dark-del-label-color);
}
.d2h-auto-color-scheme .d2h-code-line del,
.d2h-auto-color-scheme .d2h-code-side-line del {
background-color: var(--d2h-dark-del-highlight-bg-color);
}
.d2h-auto-color-scheme .d2h-code-line ins,
.d2h-auto-color-scheme .d2h-code-side-line ins {
background-color: var(--d2h-dark-ins-highlight-bg-color);
}
.d2h-auto-color-scheme .d2h-diff-tbody {
border-color: var(--d2h-dark-border-color);
}
.d2h-auto-color-scheme .d2h-code-side-linenumber {
background-color: var(--d2h-dark-bg-color);
color: var(--d2h-dark-dim-color);
border-color: var(--d2h-dark-line-border-color);
}
.d2h-auto-color-scheme .d2h-files-diff .d2h-code-side-emptyplaceholder,
.d2h-auto-color-scheme .d2h-files-diff .d2h-emptyplaceholder {
background-color: var(--d2h-dark-empty-placeholder-bg-color);
border-color: var(--d2h-dark-empty-placeholder-border-color);
}
.d2h-auto-color-scheme .d2h-code-linenumber {
background-color: var(--d2h-dark-bg-color);
color: var(--d2h-dark-dim-color);
border-color: var(--d2h-dark-line-border-color);
}
.d2h-auto-color-scheme .d2h-del {
background-color: var(--d2h-dark-del-bg-color);
border-color: var(--d2h-dark-del-border-color);
}
.d2h-auto-color-scheme .d2h-ins {
background-color: var(--d2h-dark-ins-bg-color);
border-color: var(--d2h-dark-ins-border-color);
}
.d2h-auto-color-scheme .d2h-info {
background-color: var(--d2h-dark-info-bg-color);
color: var(--d2h-dark-dim-color);
border-color: var(--d2h-dark-info-border-color);
}
.d2h-auto-color-scheme .d2h-file-diff .d2h-del.d2h-change {
background-color: var(--d2h-dark-change-del-color);
}
.d2h-auto-color-scheme .d2h-file-diff .d2h-ins.d2h-change {
background-color: var(--d2h-dark-change-ins-color);
}
.d2h-auto-color-scheme .d2h-file-wrapper {
border: 1px solid var(--d2h-dark-border-color);
}
.d2h-auto-color-scheme .d2h-file-collapse {
border: 1px solid var(--d2h-dark-bg-color);
}
.d2h-auto-color-scheme .d2h-file-collapse.d2h-selected {
background-color: var(--d2h-dark-selected-color);
}
.d2h-auto-color-scheme .d2h-file-list-wrapper a {
color: var(--d2h-dark-moved-label-color);
}
.d2h-auto-color-scheme .d2h-file-list-wrapper a:visited {
color: var(--d2h-dark-moved-label-color);
}
.d2h-auto-color-scheme .d2h-file-list > li {
border-bottom: var(--d2h-dark-bg-color) solid 1px;
}
.d2h-dark-color-scheme .d2h-deleted {
color: var(--d2h-dark-del-label-color);
}
.d2h-auto-color-scheme .d2h-added {
color: var(--d2h-dark-ins-label-color);
}
.d2h-auto-color-scheme .d2h-changed {
color: var(--d2h-dark-change-label-color);
}
.d2h-auto-color-scheme .d2h-moved {
color: var(--d2h-dark-moved-label-color);
}
.d2h-auto-color-scheme .d2h-tag {
background-color: var(--d2h-dark-bg-color);
}
.d2h-auto-color-scheme .d2h-deleted-tag {
border: var(--d2h-dark-del-label-color) 1px solid;
}
.d2h-auto-color-scheme .d2h-added-tag {
border: var(--d2h-dark-ins-label-color) 1px solid;
}
.d2h-auto-color-scheme .d2h-changed-tag {
border: var(--d2h-dark-change-label-color) 1px solid;
}
.d2h-auto-color-scheme .d2h-moved-tag {
border: var(--d2h-dark-moved-label-color) 1px solid;
}
}

View file

@ -2,7 +2,7 @@
<div class="hero-body">
<div class="container">
<h1 class="title is-size-1 is-spaced">Demo<a href="#help">
<svg height="32" class="octicon octicon-unverified" viewBox="0 0 16 16" version="1.1" width="64"
<svg fill="currentColor" height="32" class="octicon octicon-unverified" viewBox="0 0 16 16" version="1.1" width="64"
aria-hidden="true">
<path
d="M15.67 7.06l-1.08-1.34c-.17-.22-.28-.48-.31-.77l-.19-1.7a1.51 1.51 0 0 0-1.33-1.33l-1.7-.19c-.3-.03-.56-.16-.78-.33L8.94.32c-.55-.44-1.33-.44-1.88 0L5.72 1.4c-.22.17-.48.28-.77.31l-1.7.19c-.7.08-1.25.63-1.33 1.33l-.19 1.7c-.03.3-.16.56-.33.78L.32 7.05c-.44.55-.44 1.33 0 1.88l1.08 1.34c.17.22.28.48.31.77l.19 1.7c.08.7.63 1.25 1.33 1.33l1.7.19c.3.03.56.16.78.33l1.34 1.08c.55.44 1.33.44 1.88 0l1.34-1.08c.22-.17.48-.28.77-.31l1.7-.19c.7-.08 1.25-.63 1.33-1.33l.19-1.7c.03-.3.16-.56.33-.78l1.08-1.34c.44-.55.44-1.33 0-1.88zM9 11.5c0 .28-.22.5-.5.5h-1c-.27 0-.5-.22-.5-.5v-1c0-.28.23-.5.5-.5h1c.28 0 .5.22.5.5v1zm1.56-4.89c-.06.17-.17.33-.3.47-.13.16-.14.19-.33.38-.16.17-.31.3-.52.45-.11.09-.2.19-.28.27-.08.08-.14.17-.19.27-.05.1-.08.19-.11.3-.03.11-.03.13-.03.25H7.13c0-.22 0-.31.03-.48.03-.19.08-.36.14-.52.06-.14.14-.28.25-.42.11-.13.23-.25.41-.38.27-.19.36-.3.48-.52.12-.22.2-.38.2-.59 0-.27-.06-.45-.2-.58-.13-.13-.31-.19-.58-.19-.09 0-.19.02-.3.05-.11.03-.17.09-.25.16-.08.07-.14.11-.2.2a.41.41 0 0 0-.09.28h-2c0-.38.13-.56.27-.83.16-.27.36-.5.61-.67.25-.17.55-.3.88-.38.33-.08.7-.13 1.09-.13.44 0 .83.05 1.17.13.34.09.63.22.88.39.23.17.41.38.55.63.13.25.19.55.19.88 0 .22 0 .42-.08.59l-.02-.01z">
@ -33,7 +33,7 @@
</div>
<div class="columns is-desktop is-multiline">
<div class="column is-one-fifth-widescreen">
<div class="column is-one-sixth-widescreen">
<label title="Output format of the HTML, either line by line or side by side">
<p>Output Format</p>
<select class="options-label-value" id="diff-url-options-output-format" name="outputFormat">
@ -42,14 +42,24 @@
</select>
</label>
</div>
<div class="column is-one-fifth-widescreen">
<div class="column is-one-sixth-widescreen">
<label title="Color scheme to render. Auto uses user preference.">
<p>Color Scheme</p>
<select class="options-label-value" id="diff-url-options-color-scheme" name="colorScheme">
<option value="light" selected>Light</option>
<option value="dark">Dark</option>
<option value="auto">Auto</option>
</select>
</label>
</div>
<div class="column is-one-sixth-widescreen">
<label title="Show the file list summary before the diff">
<p>File Summary</p>
<input class="options-label-value" id="diff-url-options-show-files" type="checkbox" name="drawFileList"
checked />
</label>
</div>
<div class="column is-one-fifth-widescreen">
<div class="column is-one-sixth-widescreen">
<label title="Level of matching for the comparison algorithm">
<p>Matching Type</p>
<select class="options-label-value" id="diff-url-options-matching" name="matching">
@ -59,14 +69,14 @@
</select>
</label>
</div>
<div class="column is-one-fifth-widescreen">
<div class="column is-one-sixth-widescreen">
<label title="Similarity threshold for the matching algorithm">
<p>Words Threshold</p>
<input class="options-label-value" id="diff-url-options-match-words-threshold" type="number"
name="matchWordsThreshold" value="0.25" step="0.05" min="0" max="1" />
</label>
</div>
<div class="column is-one-fifth-widescreen">
<div class="column is-one-sixth-widescreen">
<label title="Maximum number of comparison performed by the matching algorithm in a block of changes">
<p>Max Comparisons</p>
<input class="options-label-value" id="diff-url-options-matching-max-comparisons" type="number"

View file

@ -5,3 +5,21 @@
.diff-url-btn.is-small {
font-size: 0.85rem;
}
.d2h-dark-color-scheme .title {
color: #fff;
}
.d2h-dark-color-scheme .footer {
background-color: #2d2d2d;
}
@media (prefers-color-scheme: dark) {
.d2h-auto-color-scheme .title {
color: #fff;
}
.d2h-auto-color-scheme .footer {
background-color: #2d2d2d;
}
}

View file

@ -2,9 +2,11 @@ import { Diff2HtmlUI, defaultDiff2HtmlUIConfig, Diff2HtmlUIConfig } from '../../
import '../../../main.ts';
import '../../../main.css';
import 'highlight.js/styles/github.css';
import './github-highlights.css';
import '../../../../src/ui/css/diff2html.css';
import './demo.css';
import { colorSchemeToCss } from '../../../../src/render-utils';
import { ColorSchemeType } from '../../../../src/types';
/*
* Example URLs:
@ -155,9 +157,16 @@ async function getDiff(request: Request): Promise<string> {
function draw(diffString: string, config: Diff2HtmlUIConfig, elements: Elements): void {
const diff2htmlUi = new Diff2HtmlUI(elements.structure.diffTarget, diffString, config);
setBodyColorScheme(diff2htmlUi.config.colorScheme);
diff2htmlUi.draw();
}
function setBodyColorScheme(colorScheme: ColorSchemeType): void {
document.body.className = colorSchemeToCss(colorScheme);
}
async function prepareInitialState(elements: Elements): Promise<[Diff2HtmlUIConfig, string]> {
const urlParams = getParamsFromSearch(window.location.search);
const currentUrl = (urlParams && urlParams[searchParam]) || 'https://github.com/rtfpessoa/diff2html/pull/106';
@ -200,6 +209,7 @@ type Elements = {
};
options: {
outputFormat: HTMLInputElement;
colorScheme: HTMLInputElement;
matching: HTMLInputElement;
wordsThreshold: HTMLInputElement;
matchingMaxComparisons: HTMLInputElement;
@ -259,6 +269,7 @@ document.addEventListener('DOMContentLoaded', async () => {
},
options: {
outputFormat: getHTMLInputElementById('diff-url-options-output-format'),
colorScheme: getHTMLInputElementById('diff-url-options-color-scheme'),
matching: getHTMLInputElementById('diff-url-options-matching'),
wordsThreshold: getHTMLInputElementById('diff-url-options-match-words-threshold'),
matchingMaxComparisons: getHTMLInputElementById('diff-url-options-matching-max-comparisons'),
@ -272,6 +283,7 @@ document.addEventListener('DOMContentLoaded', async () => {
// Update HTML inputs from any changes in URL
config.outputFormat && (elements.options.outputFormat.value = config.outputFormat);
config.colorScheme && (elements.options.colorScheme.value = config.colorScheme);
config.drawFileList && (elements.checkboxes.drawFileList.checked = config.drawFileList);
config.matching && (elements.options.matching.value = config.matching);
config.matchWordsThreshold && (elements.options.wordsThreshold.value = config.matchWordsThreshold.toString());

View file

@ -0,0 +1,332 @@
/*!
Theme Adapted from highlight.js github theme
Theme: Modified GitHub Dark
Description: Dark theme as seen on github.com, modified for diff2html demo
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-dark
Current colors taken from GitHub's CSS
*/
pre code.hljs {
display: block;
overflow-x: auto;
padding: 1em;
}
code.hljs {
padding: 3px 5px;
}
.hljs {
color: #24292e;
}
.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-variable.language_ {
color: #d73a49;
}
.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
color: #6f42c1;
}
.hljs-attr,
.hljs-attribute,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-operator,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id,
.hljs-variable {
color: #005cc5;
}
.hljs-meta .hljs-string,
.hljs-regexp,
.hljs-string {
color: #032f62;
}
.hljs-built_in,
.hljs-symbol {
color: #e36209;
}
.hljs-code,
.hljs-comment,
.hljs-formula {
color: #6a737d;
}
.hljs-name,
.hljs-quote,
.hljs-selector-pseudo,
.hljs-selector-tag {
color: #22863a;
}
.hljs-subst {
color: #24292e;
}
.hljs-section {
color: #005cc5;
font-weight: 700;
}
.hljs-bullet {
color: #735c0f;
}
.hljs-emphasis {
color: #24292e;
font-style: italic;
}
.hljs-strong {
color: #24292e;
font-weight: 700;
}
.hljs-addition {
color: #22863a;
background-color: #f0fff4;
}
.hljs-deletion {
color: #b31d28;
background-color: #ffeef0;
}
.d2h-dark-color-scheme .hljs {
color: #c9d1d9;
}
.d2h-dark-color-scheme .hljs-doctag,
.d2h-dark-color-scheme .hljs-keyword,
.d2h-dark-color-scheme .hljs-meta .hljs-keyword,
.d2h-dark-color-scheme .hljs-template-tag,
.d2h-dark-color-scheme .hljs-template-variable,
.d2h-dark-color-scheme .hljs-type,
.d2h-dark-color-scheme .hljs-variable.language_ {
color: #ff7b72;
}
.d2h-dark-color-scheme .hljs-title,
.d2h-dark-color-scheme .hljs-title.class_,
.d2h-dark-color-scheme .hljs-title.class_.inherited__,
.d2h-dark-color-scheme .hljs-title.function_ {
color: #d2a8ff;
}
.d2h-dark-color-scheme .hljs-attr,
.d2h-dark-color-scheme .hljs-attribute,
.d2h-dark-color-scheme .hljs-literal,
.d2h-dark-color-scheme .hljs-meta,
.d2h-dark-color-scheme .hljs-number,
.d2h-dark-color-scheme .hljs-operator,
.d2h-dark-color-scheme .hljs-selector-attr,
.d2h-dark-color-scheme .hljs-selector-class,
.d2h-dark-color-scheme .hljs-selector-id,
.d2h-dark-color-scheme .hljs-variable {
color: #79c0ff;
}
.d2h-dark-color-scheme .hljs-meta .hljs-string,
.d2h-dark-color-scheme .hljs-regexp,
.d2h-dark-color-scheme .hljs-string {
color: #a5d6ff;
}
.d2h-dark-color-scheme .hljs-built_in,
.d2h-dark-color-scheme .hljs-symbol {
color: #ffa657;
}
.d2h-dark-color-scheme .hljs-code,
.d2h-dark-color-scheme .hljs-comment,
.d2h-dark-color-scheme .hljs-formula {
color: #8b949e;
}
.d2h-dark-color-scheme .hljs-name,
.d2h-dark-color-scheme .hljs-quote,
.d2h-dark-color-scheme .hljs-selector-pseudo,
.d2h-dark-color-scheme .hljs-selector-tag {
color: #7ee787;
}
.d2h-dark-color-scheme .hljs-subst {
color: #c9d1d9;
}
.d2h-dark-color-scheme .hljs-section {
color: #1f6feb;
font-weight: 700;
}
.d2h-dark-color-scheme .hljs-bullet {
color: #f2cc60;
}
.d2h-dark-color-scheme .hljs-emphasis {
color: #c9d1d9;
font-style: italic;
}
.d2h-dark-color-scheme .hljs-strong {
color: #c9d1d9;
font-weight: 700;
}
.d2h-dark-color-scheme .hljs-addition {
color: #aff5b4;
background-color: #033a16;
}
.d2h-dark-color-scheme .hljs-deletion {
color: #ffdcd7;
background-color: #67060c;
}
@media (prefers-color-scheme: dark) {
.d2h-auto-color-scheme .hljs {
color: #c9d1d9;
}
.d2h-auto-color-scheme .hljs-doctag,
.d2h-auto-color-scheme .hljs-keyword,
.d2h-auto-color-scheme .hljs-meta .hljs-keyword,
.d2h-auto-color-scheme .hljs-template-tag,
.d2h-auto-color-scheme .hljs-template-variable,
.d2h-auto-color-scheme .hljs-type,
.d2h-auto-color-scheme .hljs-variable.language_ {
color: #ff7b72;
}
.d2h-auto-color-scheme .hljs-title,
.d2h-auto-color-scheme .hljs-title.class_,
.d2h-auto-color-scheme .hljs-title.class_.inherited__,
.d2h-auto-color-scheme .hljs-title.function_ {
color: #d2a8ff;
}
.d2h-auto-color-scheme .hljs-attr,
.d2h-auto-color-scheme .hljs-attribute,
.d2h-auto-color-scheme .hljs-literal,
.d2h-auto-color-scheme .hljs-meta,
.d2h-auto-color-scheme .hljs-number,
.d2h-auto-color-scheme .hljs-operator,
.d2h-auto-color-scheme .hljs-selector-attr,
.d2h-auto-color-scheme .hljs-selector-class,
.d2h-auto-color-scheme .hljs-selector-id,
.d2h-auto-color-scheme .hljs-variable {
color: #79c0ff;
}
.d2h-auto-color-scheme .hljs-meta .hljs-string,
.d2h-auto-color-scheme .hljs-regexp,
.d2h-auto-color-scheme .hljs-string {
color: #a5d6ff;
}
.d2h-auto-color-scheme .hljs-built_in,
.d2h-auto-color-scheme .hljs-symbol {
color: #ffa657;
}
.d2h-auto-color-scheme .hljs-code,
.d2h-auto-color-scheme .hljs-comment,
.d2h-auto-color-scheme .hljs-formula {
color: #8b949e;
}
.d2h-auto-color-scheme .hljs-name,
.d2h-auto-color-scheme .hljs-quote,
.d2h-auto-color-scheme .hljs-selector-pseudo,
.d2h-auto-color-scheme .hljs-selector-tag {
color: #7ee787;
}
.d2h-auto-color-scheme .hljs-subst {
color: #c9d1d9;
}
.d2h-auto-color-scheme .hljs-section {
color: #1f6feb;
font-weight: 700;
}
.d2h-auto-color-scheme .hljs-bullet {
color: #f2cc60;
}
.d2h-auto-color-scheme .hljs-emphasis {
color: #c9d1d9;
font-style: italic;
}
.d2h-auto-color-scheme .hljs-strong {
color: #c9d1d9;
font-weight: 700;
}
.d2h-auto-color-scheme .hljs-addition {
color: #aff5b4;
background-color: #033a16;
}
.d2h-auto-color-scheme .hljs-deletion {
color: #ffdcd7;
background-color: #67060c;
}
}
@media (prefers-color-scheme: light) {
.d2h-auto-color-scheme .hljs {
color: #24292e;
}
.d2h-auto-color-scheme .hljs-doctag,
.d2h-auto-color-scheme .hljs-keyword,
.d2h-auto-color-scheme .hljs-meta .hljs-keyword,
.d2h-auto-color-scheme .hljs-template-tag,
.d2h-auto-color-scheme .hljs-template-variable,
.d2h-auto-color-scheme .hljs-type,
.d2h-auto-color-scheme .hljs-variable.language_ {
color: #d73a49;
}
.d2h-auto-color-scheme .hljs-title,
.d2h-auto-color-scheme .hljs-title.class_,
.d2h-auto-color-scheme .hljs-title.class_.inherited__,
.d2h-auto-color-scheme .hljs-title.function_ {
color: #6f42c1;
}
.d2h-auto-color-scheme .hljs-attr,
.d2h-auto-color-scheme .hljs-attribute,
.d2h-auto-color-scheme .hljs-literal,
.d2h-auto-color-scheme .hljs-meta,
.d2h-auto-color-scheme .hljs-number,
.d2h-auto-color-scheme .hljs-operator,
.d2h-auto-color-scheme .hljs-selector-attr,
.d2h-auto-color-scheme .hljs-selector-class,
.d2h-auto-color-scheme .hljs-selector-id,
.d2h-auto-color-scheme .hljs-variable {
color: #005cc5;
}
.d2h-auto-color-scheme .hljs-meta .hljs-string,
.d2h-auto-color-scheme .hljs-regexp,
.d2h-auto-color-scheme .hljs-string {
color: #032f62;
}
.d2h-auto-color-scheme .hljs-built_in,
.d2h-auto-color-scheme .hljs-symbol {
color: #e36209;
}
.d2h-auto-color-scheme .hljs-code,
.d2h-auto-color-scheme .hljs-comment,
.d2h-auto-color-scheme .hljs-formula {
color: #6a737d;
}
.d2h-auto-color-scheme .hljs-name,
.d2h-auto-color-scheme .hljs-quote,
.d2h-auto-color-scheme .hljs-selector-pseudo,
.d2h-auto-color-scheme .hljs-selector-tag {
color: #22863a;
}
.d2h-auto-color-scheme .hljs-subst {
color: #24292e;
}
.d2h-auto-color-scheme .hljs-section {
color: #005cc5;
font-weight: 700;
}
.d2h-auto-color-scheme .hljs-bullet {
color: #735c0f;
}
.d2h-auto-color-scheme .hljs-emphasis {
color: #24292e;
font-style: italic;
}
.d2h-auto-color-scheme .hljs-strong {
color: #24292e;
font-weight: 700;
}
.d2h-auto-color-scheme .hljs-addition {
color: #22863a;
background-color: #f0fff4;
}
.d2h-auto-color-scheme .hljs-deletion {
color: #b31d28;
background-color: #ffeef0;
}
}