Skip to content

Commit 51fea78

Browse files
authored
Merge pull request #388 from benjamine/site
demo dark mode & json5 support
2 parents 12a23c6 + 801fd3e commit 51fea78

File tree

6 files changed

+346
-50
lines changed

6 files changed

+346
-50
lines changed

demos/html-demo/demo.ts

Lines changed: 86 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import * as jsondiffpatch from 'jsondiffpatch/with-text-diffs';
1+
import { parse as json5Parse } from 'json5';
2+
23
import * as annotatedFormatter from 'jsondiffpatch/formatters/annotated';
34
import * as htmlFormatter from 'jsondiffpatch/formatters/html';
5+
import * as jsondiffpatch from 'jsondiffpatch/with-text-diffs';
46

5-
import 'jsondiffpatch/formatters/styles/html.css';
67
import 'jsondiffpatch/formatters/styles/annotated.css';
8+
import 'jsondiffpatch/formatters/styles/html.css';
79

810
declare namespace CodeMirror {
911
function fromTextArea(
@@ -15,12 +17,15 @@ declare namespace CodeMirror {
1517
mode?: string;
1618
json?: boolean;
1719
readOnly?: boolean;
20+
theme?: string;
1821
}
1922

2023
interface Editor {
2124
getValue(): string;
2225
setValue(content: string): void;
2326
on(eventName: 'change', handler: () => void): void;
27+
refresh(): void;
28+
setOption(option: 'theme', value: string): void;
2429
}
2530
}
2631

@@ -43,6 +48,61 @@ interface Country {
4348
population?: number;
4449
}
4550

51+
const colorSchemeIsDark = () => {
52+
const colorSchemaMeta =
53+
(
54+
(document.querySelector(
55+
'meta[name="color-scheme"]',
56+
) as HTMLMetaElement) || null
57+
).content || 'default';
58+
return (
59+
colorSchemaMeta === 'only dark' ||
60+
(colorSchemaMeta !== 'only light' &&
61+
window.matchMedia('(prefers-color-scheme: dark)').matches)
62+
);
63+
};
64+
65+
const onColorSchemeChange = (handler: (dark?: boolean) => void) => {
66+
window
67+
.matchMedia('(prefers-color-scheme: dark)')
68+
.addEventListener('change', (e) => {
69+
handler(colorSchemeIsDark());
70+
});
71+
// also detect changes to the meta tag content
72+
const colorSchemaMeta = document.querySelector(
73+
'meta[name="color-scheme"]',
74+
) as HTMLMetaElement;
75+
if (colorSchemaMeta) {
76+
const observer = new MutationObserver((mutationsList) => {
77+
for (const mutation of mutationsList) {
78+
if (
79+
mutation.type === 'attributes' &&
80+
mutation.attributeName === 'content'
81+
) {
82+
handler(colorSchemeIsDark());
83+
}
84+
}
85+
});
86+
observer.observe(colorSchemaMeta, { attributes: true });
87+
}
88+
};
89+
90+
document.body.setAttribute(
91+
'data-color-scheme',
92+
colorSchemeIsDark() ? 'dark' : 'light',
93+
);
94+
onColorSchemeChange((dark) => {
95+
document.body.setAttribute('data-color-scheme', dark ? 'dark' : 'light');
96+
});
97+
98+
const parseJson = (text: string) => {
99+
try {
100+
return JSON.parse(text, jsondiffpatch.dateReviver);
101+
} catch {
102+
return json5Parse(text, jsondiffpatch.dateReviver);
103+
}
104+
};
105+
46106
const getExampleJson = function () {
47107
const data: Continent = {
48108
name: 'South America',
@@ -256,13 +316,19 @@ const dom = {
256316
url: string,
257317
callback: (error: Error | string | null, data?: unknown) => void,
258318
) {
319+
if (!url.startsWith('https://api.github.com/gists')) {
320+
return callback(
321+
null,
322+
'invalid url, for security reasons only gists are allowed',
323+
);
324+
}
259325
let request: XMLHttpRequest | null = new XMLHttpRequest();
260326
request.open('GET', url, true);
261327
request.onreadystatechange = function () {
262328
if (this.readyState === 4) {
263329
let data;
264330
try {
265-
data = JSON.parse(this.responseText, jsondiffpatch.dateReviver);
331+
data = parseJson(this.responseText);
266332
} catch (parseError) {
267333
return callback('parse error: ' + parseError);
268334
}
@@ -337,7 +403,7 @@ class JsonArea {
337403
/^["].*["]$/.test(txt) ||
338404
/^[{[](.|\n)*[}\]]$/.test(txt)
339405
) {
340-
return JSON.parse(txt, jsondiffpatch.dateReviver);
406+
return parseJson(txt);
341407
}
342408
return this.getValue();
343409
} catch (err) {
@@ -366,11 +432,22 @@ class JsonArea {
366432
if (typeof CodeMirror === 'undefined') {
367433
return;
368434
}
369-
this.editor = CodeMirror.fromTextArea(this.element, {
435+
436+
// Function to get current theme based on browser's interpreted scheme
437+
const getTheme = () => (colorSchemeIsDark() ? 'monokai' : 'default');
438+
439+
const editor = CodeMirror.fromTextArea(this.element, {
370440
mode: 'javascript',
371441
json: true,
372442
readOnly,
443+
theme: getTheme(),
444+
});
445+
this.editor = editor;
446+
447+
onColorSchemeChange(() => {
448+
editor.setOption('theme', getTheme());
373449
});
450+
374451
if (!readOnly) {
375452
this.editor.on('change', compare);
376453
}
@@ -465,6 +542,7 @@ const compare = function () {
465542

466543
areas.left.makeEditor();
467544
areas.right.makeEditor();
545+
areas.delta.makeEditor(true);
468546

469547
areas.left.element.addEventListener('change', compare);
470548
areas.right.element.addEventListener('change', compare);
@@ -501,6 +579,9 @@ const showSelectedDeltaType = function () {
501579
document.getElementById('delta-panel-json')!.style.display =
502580
type === 'json' ? '' : 'none';
503581
compare();
582+
if (type === 'json') {
583+
areas.delta.editor!.refresh();
584+
}
504585
};
505586

506587
document
@@ -821,18 +902,6 @@ if (urlQuery) {
821902
}),
822903
);
823904
break;
824-
case 'urls':
825-
document.location =
826-
'?desc=http%20raw%20file%20urls&left=' +
827-
encodeURIComponent(
828-
'https://rawgithub.com/benjamine/JsonDiffPatch/' +
829-
'c83e942971c627f61ef874df3cfdd50a95f1c5a2/package.json',
830-
) +
831-
'&right=' +
832-
encodeURIComponent(
833-
'https://rawgithub.com/benjamine/JsonDiffPatch/master/package.json',
834-
);
835-
break;
836905
default:
837906
document.location = '?';
838907
break;

0 commit comments

Comments
 (0)