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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<!-- <div>[<strong>RAW</strong> / <a href="/react">REACT</a>]</div> -->
</div>
</div>
<div id="content" class="content" />
<div id="wrapper" class="wrapper" />
</div>
<script type="module" src="/src/main.ts"></script>
</body>
Expand Down
131 changes: 69 additions & 62 deletions apps/demo/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
import {
CodeRenderer,
DiffRenderer,
DiffFileRenderer,
type ParsedPatch,
type SupportedLanguages,
getFiletypeFromFileName,
isHighlighterNull,
parseDiffFromFiles,
parsePatchContent,
preloadHighlighter,
renderFileHeader,
} from '@pierre/diff-ui';
import type { BundledLanguage, BundledTheme } from 'shiki';

import {
DIFF_CONTENT as CONTENT,
CodeConfigs,
FILE_NEW,
FILE_OLD,
getFiletypeFromMetadata,
toggleTheme,
} from './mocks/';
import { CodeConfigs, FILE_NEW, FILE_OLD, toggleTheme } from './mocks/';
import './style.css';
import { createFakeContentStream } from './utils/createFakeContentStream';

let loadingPatch: Promise<string> | undefined;
async function loadPatchContent() {
loadingPatch =
loadingPatch ??
new Promise((resolve) => {
import('./mocks/diff.patch?raw').then(({ default: content }) =>
resolve(content)
);
});
return loadingPatch;
}

function startStreaming() {
const container = document.getElementById('content');
const container = document.getElementById('wrapper');
if (container == null) return;
if (loadDiff != null) {
loadDiff.parentElement?.removeChild(loadDiff);
Expand All @@ -39,14 +45,15 @@ function startStreaming() {
}

let parsedPatches: ParsedPatch[] | undefined;
function handlePreloadDiff() {
async function handlePreloadDiff() {
if (parsedPatches != null || !isHighlighterNull()) return;
parsedPatches = parsePatchContent(CONTENT);
const content = await loadPatchContent();
parsedPatches = parsePatchContent(content);
console.log('Parsed File:', parsedPatches);
const langs = new Set<BundledLanguage>();
const langs = new Set<SupportedLanguages>();
for (const parsedPatch of parsedPatches) {
for (const file of parsedPatch.files) {
const lang = getFiletypeFromMetadata(file);
const lang = getFiletypeFromFileName(file.name);
if (lang != null) {
langs.add(lang);
}
Expand All @@ -58,42 +65,39 @@ function handlePreloadDiff() {
});
}

const diffInstances: DiffRenderer[] = [];
const diffInstances: DiffFileRenderer[] = [];
function renderDiff(parsedPatches: ParsedPatch[]) {
const container = document.getElementById('content');
if (container == null) return;
const wrapper = document.getElementById('wrapper');
if (wrapper == null) return;
if (loadDiff != null) {
loadDiff.parentElement?.removeChild(loadDiff);
}
if (streamCode != null) {
streamCode.parentElement?.removeChild(streamCode);
}
container.innerHTML = '';
wrapper.innerHTML = '';
window.scrollTo({ top: 0 });
for (const instance of diffInstances) {
instance.cleanUp();
}
diffInstances.length = 0;
container.dataset.diff = '';
wrapper.dataset.diff = '';

const checkbox = document.getElementById('unified') as
| HTMLInputElement
| undefined;
const unified = checkbox?.checked ?? false;
for (const parsedPatch of parsedPatches) {
if (parsedPatch.patchMetadata != null) {
container.appendChild(createFileMetadata(parsedPatch.patchMetadata));
wrapper.appendChild(createFileMetadata(parsedPatch.patchMetadata));
}
for (const file of parsedPatch.files) {
container.appendChild(renderFileHeader(file));
const pre = document.createElement('pre');
container.appendChild(pre);
const instance = new DiffRenderer({
lang: getFiletypeFromMetadata(file),
for (const fileDiff of parsedPatch.files) {
const instance = new DiffFileRenderer({
themes: { dark: 'tokyo-night', light: 'solarized-light' },
unified,
diffStyle: unified ? 'unified' : 'split',
detectLanguage: true,
});
instance.render(file, pre);
instance.render({ fileDiff, wrapper });
diffInstances.push(instance);
}
}
Expand Down Expand Up @@ -134,9 +138,9 @@ if (streamCode != null) {

const loadDiff = document.getElementById('load-diff');
if (loadDiff != null) {
loadDiff.addEventListener('click', () =>
renderDiff(parsedPatches ?? parsePatchContent(CONTENT))
);
loadDiff.addEventListener('click', async () => {
renderDiff(parsedPatches ?? parsePatchContent(await loadPatchContent()));
});
loadDiff.addEventListener('mouseenter', handlePreloadDiff);
}

Expand Down Expand Up @@ -166,7 +170,10 @@ if (unifiedCheckbox instanceof HTMLInputElement) {
unifiedCheckbox.addEventListener('change', () => {
const checked = unifiedCheckbox.checked;
for (const instance of diffInstances) {
instance.setOptions({ ...instance.options, unified: checked });
instance.setOptions({
...instance.options,
diffStyle: checked ? 'unified' : 'split',
});
}
});
}
Expand All @@ -180,46 +187,46 @@ if (diff2Files != null) {
}
lastWrapper = document.createElement('div');

const file1Container = document.createElement('div');
file1Container.className = 'file';
const fileOldContainer = document.createElement('div');
fileOldContainer.className = 'file';
lastWrapper.className = 'files-input';
const file1Name = document.createElement('input');
file1Name.type = 'text';
file1Name.value = 'file_old.ts';
file1Name.spellcheck = false;
const file1Contents = document.createElement('textarea');
file1Contents.value = FILE_OLD;
file1Contents.spellcheck = false;
file1Container.appendChild(file1Name);
file1Container.appendChild(file1Contents);
lastWrapper.appendChild(file1Container);

const file2Container = document.createElement('div');
file2Container.className = 'file';
const fileOldName = document.createElement('input');
fileOldName.type = 'text';
fileOldName.value = 'file_old.ts';
fileOldName.spellcheck = false;
const fileOldContents = document.createElement('textarea');
fileOldContents.value = FILE_OLD;
fileOldContents.spellcheck = false;
fileOldContainer.appendChild(fileOldName);
fileOldContainer.appendChild(fileOldContents);
lastWrapper.appendChild(fileOldContainer);

const fileNewContainer = document.createElement('div');
fileNewContainer.className = 'file';
lastWrapper.className = 'files-input';
const file2Name = document.createElement('input');
file2Name.type = 'text';
file2Name.value = 'file_new.ts';
file2Name.spellcheck = false;
const file2Contents = document.createElement('textarea');
file2Contents.value = FILE_NEW;
file2Contents.spellcheck = false;
file2Container.appendChild(file2Name);
file2Container.appendChild(file2Contents);
lastWrapper.appendChild(file2Container);
const fileNewName = document.createElement('input');
fileNewName.type = 'text';
fileNewName.value = 'file_new.ts';
fileNewName.spellcheck = false;
const fileNewContents = document.createElement('textarea');
fileNewContents.value = FILE_NEW;
fileNewContents.spellcheck = false;
fileNewContainer.appendChild(fileNewName);
fileNewContainer.appendChild(fileNewContents);
lastWrapper.appendChild(fileNewContainer);

const bottomWrapper = document.createElement('div');
bottomWrapper.className = 'buttons';
const render = document.createElement('button');
render.innerText = 'Render Diff';
render.addEventListener('click', () => {
const oldFile = {
name: file1Name.value,
contents: file1Contents.value,
name: fileOldName.value,
contents: fileOldContents.value,
};
const newFile = {
name: file2Name.value,
contents: file2Contents.value,
name: fileNewName.value,
contents: fileNewContents.value,
};

lastWrapper?.parentNode?.removeChild(lastWrapper);
Expand Down
30 changes: 0 additions & 30 deletions apps/demo/src/mocks/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
import type { FileMetadata } from '@pierre/diff-ui';
import type { BundledLanguage } from 'shiki';

import { createHighlighterCleanup } from '../utils/createHighlighterCleanup';
import { createScrollFixer } from '../utils/createScrollFixer';
import diffContent2 from './diff2.patch?raw';
import diffContent3 from './diff3.patch?raw';
import diffContent4 from './diff4.patch?raw';
import diffContent5 from './diff5.patch?raw';
import diffContent from './diff.patch?raw';
import mdContent from './example_md.txt?raw';
import tsContent from './example_ts.txt?raw';
import fileNew from './fileNew.txt?raw';
Expand Down Expand Up @@ -53,25 +45,3 @@ export function toggleTheme() {

export const FILE_OLD = fileOld;
export const FILE_NEW = fileNew;

export const DIFF_CONTENT = diffContent;
export const DIFF_CONTENT_2 = diffContent2;
export const DIFF_CONTENT_3 = diffContent3;
export const DIFF_CONTENT_4 = diffContent4;
export const DIFF_CONTENT_5 = diffContent5;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undoing the sins of my past here. No reason to bundle these in with the JS, should import() them, which now I do


export const DIFF_CONTENT_FORMATS: Record<string, BundledLanguage | undefined> =
{
js: 'javascript',
jsx: 'jsx',
html: 'html',
json: 'json',
ts: 'typescript',
tsx: 'tsx',
css: 'css',
patch: 'diff',
};

export function getFiletypeFromMetadata(file: FileMetadata) {
return DIFF_CONTENT_FORMATS[file.name.match(/\.([^.]+)$/)?.[1] || ''];
}
13 changes: 11 additions & 2 deletions apps/demo/src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ code {
align-items: center;
}

.content {
.wrapper {
display: grid;
min-width: 0;
min-height: 0;
Expand All @@ -147,7 +147,7 @@ code {
overflow: hidden;
}

.content[data-diff] {
.wrapper[data-diff] {
grid-template-columns: 1fr;
grid-template-rows: min-content;
min-height: auto;
Expand Down Expand Up @@ -225,3 +225,12 @@ code {
display: flex;
flex-direction: row-reverse;
}

[data-pjs],
[data-pjs-header] {
content-visibility: auto;
}

[data-pjs-header] {
contain-intrinsic-size: auto 36px;
}
Loading