mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-08 15:15:02 -04:00
feat(json-diff): add new tool to get the diff of two given JSONs
This commit is contained in:
parent
7d7cc99866
commit
80af4a3eea
9 changed files with 559 additions and 1 deletions
|
@ -56,6 +56,7 @@
|
|||
"fuse.js": "^6.6.2",
|
||||
"highlight.js": "^11.7.0",
|
||||
"json5": "^2.2.3",
|
||||
"jsondiffpatch-rc": "^0.4.2",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"lodash": "^4.17.21",
|
||||
"mathjs": "^10.6.4",
|
||||
|
@ -68,6 +69,7 @@
|
|||
"plausible-tracker": "^0.3.8",
|
||||
"qrcode": "^1.5.1",
|
||||
"randombytes": "^2.1.0",
|
||||
"sanitize-html": "^2.10.0",
|
||||
"sql-formatter": "^8.2.0",
|
||||
"ts-pattern": "^4.2.2",
|
||||
"ua-parser-js": "^1.0.35",
|
||||
|
|
77
pnpm-lock.yaml
generated
77
pnpm-lock.yaml
generated
|
@ -70,6 +70,9 @@ dependencies:
|
|||
json5:
|
||||
specifier: ^2.2.3
|
||||
version: 2.2.3
|
||||
jsondiffpatch-rc:
|
||||
specifier: ^0.4.2
|
||||
version: 0.4.2
|
||||
jwt-decode:
|
||||
specifier: ^3.1.2
|
||||
version: 3.1.2
|
||||
|
@ -106,6 +109,9 @@ dependencies:
|
|||
randombytes:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
sanitize-html:
|
||||
specifier: ^2.10.0
|
||||
version: 2.10.0
|
||||
sql-formatter:
|
||||
specifier: ^8.2.0
|
||||
version: 8.2.0
|
||||
|
@ -4039,6 +4045,10 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/diff-match-patch@1.0.5:
|
||||
resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==}
|
||||
dev: false
|
||||
|
||||
/dijkstrajs@1.0.2:
|
||||
resolution: {integrity: sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==}
|
||||
dev: false
|
||||
|
@ -4076,9 +4086,16 @@ packages:
|
|||
entities: 2.2.0
|
||||
dev: true
|
||||
|
||||
/dom-serializer@2.0.0:
|
||||
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
entities: 4.4.0
|
||||
dev: false
|
||||
|
||||
/domelementtype@2.3.0:
|
||||
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
|
||||
dev: true
|
||||
|
||||
/domexception@4.0.0:
|
||||
resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==}
|
||||
|
@ -4094,6 +4111,13 @@ packages:
|
|||
domelementtype: 2.3.0
|
||||
dev: true
|
||||
|
||||
/domhandler@5.0.3:
|
||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||
engines: {node: '>= 4'}
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
dev: false
|
||||
|
||||
/domutils@2.8.0:
|
||||
resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
|
||||
dependencies:
|
||||
|
@ -4102,6 +4126,14 @@ packages:
|
|||
domhandler: 4.3.1
|
||||
dev: true
|
||||
|
||||
/domutils@3.0.1:
|
||||
resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==}
|
||||
dependencies:
|
||||
dom-serializer: 2.0.0
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
dev: false
|
||||
|
||||
/dot-case@3.0.4:
|
||||
resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
|
||||
dependencies:
|
||||
|
@ -4184,6 +4216,11 @@ packages:
|
|||
resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
/entities@4.4.0:
|
||||
resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==}
|
||||
engines: {node: '>=0.12'}
|
||||
dev: false
|
||||
|
||||
/errno@0.1.8:
|
||||
resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==}
|
||||
hasBin: true
|
||||
|
@ -5349,6 +5386,15 @@ packages:
|
|||
entities: 3.0.1
|
||||
dev: true
|
||||
|
||||
/htmlparser2@8.0.2:
|
||||
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
domutils: 3.0.1
|
||||
entities: 4.4.0
|
||||
dev: false
|
||||
|
||||
/http-proxy-agent@4.0.1:
|
||||
resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==}
|
||||
engines: {node: '>= 6'}
|
||||
|
@ -5611,6 +5657,11 @@ packages:
|
|||
isobject: 3.0.1
|
||||
dev: false
|
||||
|
||||
/is-plain-object@5.0.0:
|
||||
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/is-potential-custom-element-name@1.0.1:
|
||||
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
|
||||
dev: true
|
||||
|
@ -5924,6 +5975,15 @@ packages:
|
|||
resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
|
||||
dev: true
|
||||
|
||||
/jsondiffpatch-rc@0.4.2:
|
||||
resolution: {integrity: sha512-Y1qBHcinsSX6E24KvYEAzybrmhnyy/eg2uhablTW76oKrdY0nYeWoXRlMCvTXG0Nv/zlzGwAfb3mxg1JzitLug==}
|
||||
engines: {node: '>=8.17.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
diff-match-patch: 1.0.5
|
||||
dev: false
|
||||
bundledDependencies: []
|
||||
|
||||
/jsonfile@6.1.0:
|
||||
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
|
||||
dependencies:
|
||||
|
@ -6698,6 +6758,10 @@ packages:
|
|||
engines: {node: '>= 0.10'}
|
||||
dev: true
|
||||
|
||||
/parse-srcset@1.0.2:
|
||||
resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
|
||||
dev: false
|
||||
|
||||
/parse5@6.0.1:
|
||||
resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==}
|
||||
dev: true
|
||||
|
@ -7422,6 +7486,17 @@ packages:
|
|||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||
dev: true
|
||||
|
||||
/sanitize-html@2.10.0:
|
||||
resolution: {integrity: sha512-JqdovUd81dG4k87vZt6uA6YhDfWkUGruUu/aPmXLxXi45gZExnt9Bnw/qeQU8oGf82vPyaE0vO4aH0PbobB9JQ==}
|
||||
dependencies:
|
||||
deepmerge: 4.3.1
|
||||
escape-string-regexp: 4.0.0
|
||||
htmlparser2: 8.0.2
|
||||
is-plain-object: 5.0.0
|
||||
parse-srcset: 1.0.2
|
||||
postcss: 8.4.21
|
||||
dev: false
|
||||
|
||||
/sax@1.2.4:
|
||||
resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==}
|
||||
dev: true
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { tool as base64FileConverter } from './base64-file-converter';
|
||||
import { tool as base64StringConverter } from './base64-string-converter';
|
||||
import { tool as basicAuthGenerator } from './basic-auth-generator';
|
||||
import { tool as jsonDiff } from './json-diff';
|
||||
import { tool as yamlToJson } from './yaml-to-json-converter';
|
||||
import { tool as jsonToYaml } from './json-to-yaml-converter';
|
||||
import { tool as ipv6UlaGenerator } from './ipv6-ula-generator';
|
||||
|
@ -102,6 +103,7 @@ export const toolsByCategory: ToolCategory[] = [
|
|||
crontabGenerator,
|
||||
jsonViewer,
|
||||
jsonMinify,
|
||||
jsonDiff,
|
||||
sqlPrettify,
|
||||
chmodCalculator,
|
||||
dockerRunToDockerComposeConverter,
|
||||
|
|
12
src/tools/json-diff/index.ts
Normal file
12
src/tools/json-diff/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { ArrowsShuffle } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'JSON diff',
|
||||
path: '/json-diff',
|
||||
description: 'Compares two given JSONs and build a visual comparison of them',
|
||||
keywords: ['json', 'diff', 'visual'],
|
||||
component: () => import('./json-diff.vue'),
|
||||
icon: ArrowsShuffle,
|
||||
createdAt: new Date('2023-04-12'),
|
||||
});
|
70
src/tools/json-diff/json-diff-result.vue
Normal file
70
src/tools/json-diff/json-diff-result.vue
Normal file
|
@ -0,0 +1,70 @@
|
|||
<template>
|
||||
<div style="flex: 0 0 100%">
|
||||
<n-space style="margin: 0 auto; max-width: 600px" justify="center">
|
||||
<n-form-item label="Show unchanged :" label-placement="left" label-width="160">
|
||||
<n-switch v-model:value="showUnchanged" :disabled="!validInput" />
|
||||
</n-form-item>
|
||||
</n-space>
|
||||
</div>
|
||||
|
||||
<div style="flex: 0 0 100%">
|
||||
<n-space style="margin: 0 auto; max-width: 600px" justify="center">
|
||||
<n-card title="Diff result" data-test-id="result">
|
||||
<div ref="result">
|
||||
<SanitizedHtml :html="diffResult" />
|
||||
</div>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, toRefs } from 'vue';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
import JSON5 from 'json5';
|
||||
import { DiffPatcher, formatters } from 'jsondiffpatch-rc';
|
||||
import SanitizedHtml from './sanitized-html.vue';
|
||||
import './styles.css';
|
||||
|
||||
const result = ref<HTMLDivElement | null>(null);
|
||||
|
||||
onMounted(() => {
|
||||
showHideUnchanged();
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<{ left: string; right: string }>(), { left: '', right: '' });
|
||||
const { left, right } = toRefs(props);
|
||||
const showUnchanged = ref(true);
|
||||
|
||||
const leftJson = computed(() => withDefaultOnError(() => JSON5.parse(left.value), ''));
|
||||
const rightJson = computed(() => withDefaultOnError(() => JSON5.parse(right.value), ''));
|
||||
const diffResult = computed(() => {
|
||||
if (!validInput.value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const diffPatcher = new DiffPatcher({
|
||||
objectHash: function (obj, index) {
|
||||
if (typeof obj._id !== 'undefined') {
|
||||
return obj._id;
|
||||
}
|
||||
if (typeof obj.id !== 'undefined') {
|
||||
return obj.id;
|
||||
}
|
||||
return '$$index:' + index;
|
||||
},
|
||||
arrays: { detectMove: true, includeValueOnMove: true },
|
||||
});
|
||||
const delta = diffPatcher.diff(leftJson.value, rightJson.value);
|
||||
return delta === undefined ? 'both JSONs are identical' : formatters.html.format(delta, leftJson.value);
|
||||
});
|
||||
const validInput = computed(() => leftJson.value !== '' && rightJson.value !== '');
|
||||
|
||||
watch([diffResult, showUnchanged], () => showHideUnchanged(), { immediate: true });
|
||||
|
||||
function showHideUnchanged() {
|
||||
if (result.value) {
|
||||
formatters.html.showUnchanged(showUnchanged.value, result.value, 200);
|
||||
}
|
||||
}
|
||||
</script>
|
28
src/tools/json-diff/json-diff.e2e.spec.ts
Normal file
28
src/tools/json-diff/json-diff.e2e.spec.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Tool - Json diff', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/json-diff');
|
||||
});
|
||||
|
||||
test('Has correct title', async ({ page }) => {
|
||||
await expect(page).toHaveTitle('JSON diff - IT Tools');
|
||||
});
|
||||
|
||||
test('Compare two identical JSONs with corresponding result message', async ({ page }) => {
|
||||
const json = '{"foo":"bar","list":["item",{"key":"value"}]}';
|
||||
await page.getByTestId('leftJson').fill(json);
|
||||
await page.getByTestId('rightJson').fill(json);
|
||||
|
||||
const generatedResult = await page.getByTestId('result').innerText();
|
||||
|
||||
expect(generatedResult.trim()).toContain('both JSONs are identical');
|
||||
});
|
||||
|
||||
test('Compare two different JSONs with corresponding result message', async ({ page }) => {
|
||||
await page.getByTestId('leftJson').fill('{"foo":"bar","list":["item","item2",{"key":"value"}]}');
|
||||
await page.getByTestId('rightJson').fill('{"foo":"bar","list":["item",{"key":"value"}]}');
|
||||
|
||||
await expect(page.getByTestId('result').getByRole('listitem')).toHaveCount(6);
|
||||
});
|
||||
});
|
146
src/tools/json-diff/json-diff.vue
Normal file
146
src/tools/json-diff/json-diff.vue
Normal file
|
@ -0,0 +1,146 @@
|
|||
<template>
|
||||
<n-form-item
|
||||
label="Your first json"
|
||||
:feedback="leftJsonValidation.message"
|
||||
:validation-status="leftJsonValidation.status"
|
||||
>
|
||||
<n-input
|
||||
v-model:value="rawLeftJson"
|
||||
placeholder="Paste your first json here..."
|
||||
type="textarea"
|
||||
rows="20"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
autocapitalize="off"
|
||||
spellcheck="false"
|
||||
:input-props="{ 'data-test-id': 'leftJson' }"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item
|
||||
label="Your json to compare"
|
||||
:feedback="rightJsonValidation.message"
|
||||
:validation-status="rightJsonValidation.status"
|
||||
>
|
||||
<n-input
|
||||
v-model:value="rawRightJson"
|
||||
placeholder="Paste your json to compare here..."
|
||||
type="textarea"
|
||||
rows="20"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
autocapitalize="off"
|
||||
spellcheck="false"
|
||||
:input-props="{ 'data-test-id': 'rightJson' }"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<JsonDiffResult :left="rawLeftJson" :right="rawRightJson" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useStorage } from '@vueuse/core';
|
||||
import { useValidation } from '@/composable/validation';
|
||||
import JSON5 from 'json5';
|
||||
import JsonDiffResult from './json-diff-result.vue';
|
||||
|
||||
const rawLeftJson = useStorage(
|
||||
'json-compare:left-json',
|
||||
`{
|
||||
"Actors": [
|
||||
{
|
||||
"name": "Tom Cruise",
|
||||
"age": 56,
|
||||
"Born At": "Syracuse, NY",
|
||||
"Birthdate": "July 3, 1962",
|
||||
"photo": "https://jsonformatter.org/img/tom-cruise.jpg",
|
||||
"wife": null,
|
||||
"weight": 67.5,
|
||||
"hasChildren": true,
|
||||
"hasGreyHair": false,
|
||||
"children": [
|
||||
"Suri",
|
||||
"Isabella Jane",
|
||||
"Connor"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Robert Downey Jr.",
|
||||
"age": 53,
|
||||
"Born At": "New York City, NY",
|
||||
"Birthdate": "April 4, 1965",
|
||||
"photo": "https://jsonformatter.org/img/Robert-Downey-Jr.jpg",
|
||||
"wife": "Susan Downey",
|
||||
"weight": 77.1,
|
||||
"hasChildren": true,
|
||||
"hasGreyHair": false,
|
||||
"children": [
|
||||
"Indio Falconer",
|
||||
"Avri Roel",
|
||||
"Exton Elias"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
);
|
||||
const rawRightJson = useStorage(
|
||||
'json-compare:right-json',
|
||||
`{
|
||||
"Actors": [
|
||||
{
|
||||
"name": "Tom Cruise",
|
||||
"age": 56,
|
||||
"Born At": "Syracuse, NY",
|
||||
"Birthdate": "July 3, 1962",
|
||||
"photo": "https://jsonformatter.org/img/tom-cruise.jpg",
|
||||
"wife": null,
|
||||
"weight": 57.7,
|
||||
"hasChildren": true,
|
||||
"hasGreyHair": false,
|
||||
"children": [
|
||||
"Connor",
|
||||
"Suri",
|
||||
"Isabella Jane"
|
||||
],
|
||||
"favoriteFood": "Spaghetti"
|
||||
},
|
||||
{
|
||||
"name": "Robert Downey Sr.",
|
||||
"age": 53,
|
||||
"Born At": "New York City, NY",
|
||||
"Birthdate": "April 4, 1965",
|
||||
"photo": "https://jsonformatter.org/img/Robert-Downey-Jr.jpg",
|
||||
"weight": 77.1,
|
||||
"hasChildren": true,
|
||||
"hasGreyHair": false,
|
||||
"children": [
|
||||
"Indio Falconer",
|
||||
"Avri Roel",
|
||||
"Exton Elias"
|
||||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
);
|
||||
|
||||
const leftJsonValidation = useValidation({
|
||||
source: rawLeftJson,
|
||||
rules: [
|
||||
{
|
||||
validator: (v) => v === '' || JSON5.parse(v),
|
||||
message: 'Provided JSON is not valid.',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const rightJsonValidation = useValidation({
|
||||
source: rawRightJson,
|
||||
rules: [
|
||||
{
|
||||
validator: (v) => v === '' || JSON5.parse(v),
|
||||
message: 'Provided JSON is not valid.',
|
||||
},
|
||||
],
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
39
src/tools/json-diff/sanitized-html.vue
Normal file
39
src/tools/json-diff/sanitized-html.vue
Normal file
|
@ -0,0 +1,39 @@
|
|||
<template>
|
||||
<span ref="block"></span>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import sanitizeHtml from 'sanitize-html';
|
||||
import { Ref, ref, watch } from 'vue';
|
||||
|
||||
const block = ref() as Ref<HTMLSpanElement>;
|
||||
|
||||
const props = withDefaults(defineProps<{ html: string }>(), { html: undefined });
|
||||
|
||||
let options = {
|
||||
allowedTags: ['div', 'ul', 'li', 'pre'],
|
||||
allowedAttributes: {
|
||||
div: ['class'],
|
||||
ul: ['class'],
|
||||
li: ['class', 'data-key'],
|
||||
},
|
||||
};
|
||||
|
||||
const onUpdateContent = () => {
|
||||
if (block.value) {
|
||||
block.value.innerHTML = sanitizeHtml(props.html, options);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
onUpdateContent();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.html as string | undefined,
|
||||
() => {
|
||||
onUpdateContent();
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
184
src/tools/json-diff/styles.css
Normal file
184
src/tools/json-diff/styles.css
Normal file
|
@ -0,0 +1,184 @@
|
|||
:root {
|
||||
--jsdiff-color_fg: #888888ff;
|
||||
--jsdiff-color_fg_location: #bbbbbbff;
|
||||
--jsdiff-color_bg_added: #066f1988;
|
||||
--jsdiff-color_bg_deleted: #ab060988;
|
||||
--jsdiff-color_bg_moved: #ffffbbff;
|
||||
--jsdiff-font_family: monospace;
|
||||
}
|
||||
.jsondiffpatch-delta {
|
||||
font-family: var(--jsdiff-font_family);
|
||||
margin: 0;
|
||||
padding: 0 0 0 12px;
|
||||
display: inline-block;
|
||||
}
|
||||
.jsondiffpatch-delta pre {
|
||||
font-family: var(--jsdiff-font_family);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
.jsondiffpatch-delta ul {
|
||||
list-style-type: none;
|
||||
padding: 0 0 0 20px;
|
||||
margin: 0;
|
||||
}
|
||||
ul.jsondiffpatch-delta {
|
||||
list-style-type: none;
|
||||
padding: 0 0 0 20px;
|
||||
margin: 0;
|
||||
}
|
||||
.jsondiffpatch-added .jsondiffpatch-property-name {
|
||||
background: var(--jsdiff-color_bg_added);
|
||||
}
|
||||
.jsondiffpatch-added .jsondiffpatch-value pre {
|
||||
background: var(--jsdiff-color_bg_added);
|
||||
}
|
||||
.jsondiffpatch-modified .jsondiffpatch-right-value {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.jsondiffpatch-modified .jsondiffpatch-right-value pre {
|
||||
background: var(--jsdiff-color_bg_added);
|
||||
}
|
||||
.jsondiffpatch-modified .jsondiffpatch-left-value pre {
|
||||
background: var(--jsdiff-color_bg_deleted);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.jsondiffpatch-modified >.jsondiffpatch-left-value pre:after {
|
||||
content: '';
|
||||
}
|
||||
.jsondiffpatch-modified .jsondiffpatch-value {
|
||||
display: inline-block;
|
||||
}
|
||||
.jsondiffpatch-textdiff-added {
|
||||
background: var(--jsdiff-color_bg_added);
|
||||
}
|
||||
.jsondiffpatch-deleted .jsondiffpatch-property-name {
|
||||
background: var(--jsdiff-color_bg_deleted);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.jsondiffpatch-deleted pre {
|
||||
background: var(--jsdiff-color_bg_deleted);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.jsondiffpatch-textdiff-deleted {
|
||||
background: var(--jsdiff-color_bg_deleted);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.jsondiffpatch-unchanged {
|
||||
color: var(--jsdiff-color_fg);
|
||||
transition: all 0.5s;
|
||||
-webkit-transition: all 0.5s;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.jsondiffpatch-movedestination {
|
||||
color: var(--jsdiff-color_fg);
|
||||
}
|
||||
.jsondiffpatch-movedestination >.jsondiffpatch-value {
|
||||
transition: all 0.5s;
|
||||
-webkit-transition: all 0.5s;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.jsondiffpatch-unchanged-showing .jsondiffpatch-unchanged {
|
||||
max-height: 100px;
|
||||
}
|
||||
.jsondiffpatch-unchanged-showing .jsondiffpatch-movedestination >.jsondiffpatch-value {
|
||||
max-height: 100px;
|
||||
}
|
||||
.jsondiffpatch-unchanged-showing .jsondiffpatch-arrow {
|
||||
display: none;
|
||||
}
|
||||
.jsondiffpatch-unchanged-hidden .jsondiffpatch-unchanged {
|
||||
max-height: 0;
|
||||
}
|
||||
.jsondiffpatch-unchanged-hidden .jsondiffpatch-movedestination >.jsondiffpatch-value {
|
||||
max-height: 0;
|
||||
display: block;
|
||||
}
|
||||
.jsondiffpatch-unchanged-hiding .jsondiffpatch-movedestination >.jsondiffpatch-value {
|
||||
display: block;
|
||||
max-height: 0;
|
||||
}
|
||||
.jsondiffpatch-unchanged-hiding .jsondiffpatch-unchanged {
|
||||
max-height: 0;
|
||||
}
|
||||
.jsondiffpatch-unchanged-hiding .jsondiffpatch-arrow {
|
||||
display: none;
|
||||
}
|
||||
.jsondiffpatch-unchanged-visible .jsondiffpatch-unchanged {
|
||||
max-height: 100px;
|
||||
}
|
||||
.jsondiffpatch-unchanged-visible .jsondiffpatch-movedestination >.jsondiffpatch-value {
|
||||
max-height: 100px;
|
||||
}
|
||||
.jsondiffpatch-value {
|
||||
display: inline-block;
|
||||
}
|
||||
.jsondiffpatch-value pre:after {
|
||||
content: ',';
|
||||
}
|
||||
.jsondiffpatch-property-name {
|
||||
display: inline-block;
|
||||
padding-right: 5px;
|
||||
vertical-align: top;
|
||||
}
|
||||
.jsondiffpatch-property-name:after {
|
||||
content: ': ';
|
||||
}
|
||||
.jsondiffpatch-child-node-type-array >.jsondiffpatch-property-name:after {
|
||||
content: ': [';
|
||||
}
|
||||
.jsondiffpatch-child-node-type-array:after {
|
||||
content: '],';
|
||||
}
|
||||
div.jsondiffpatch-child-node-type-array:before {
|
||||
content: '[';
|
||||
}
|
||||
div.jsondiffpatch-child-node-type-array:after {
|
||||
content: ']';
|
||||
}
|
||||
.jsondiffpatch-child-node-type-object >.jsondiffpatch-property-name:after {
|
||||
content: ': {';
|
||||
}
|
||||
.jsondiffpatch-child-node-type-object:after {
|
||||
content: '},';
|
||||
}
|
||||
div.jsondiffpatch-child-node-type-object:before {
|
||||
content: '{';
|
||||
}
|
||||
div.jsondiffpatch-child-node-type-object:after {
|
||||
content: '}';
|
||||
}
|
||||
li:last-child >.jsondiffpatch-value pre:after {
|
||||
content: '';
|
||||
}
|
||||
.jsondiffpatch-moved .jsondiffpatch-value {
|
||||
display: none;
|
||||
}
|
||||
.jsondiffpatch-moved .jsondiffpatch-moved-destination {
|
||||
display: inline-block;
|
||||
background: var(--jsdiff-color_bg_moved);
|
||||
color: var(--jsdiff-color_fg);
|
||||
}
|
||||
.jsondiffpatch-moved .jsondiffpatch-moved-destination:before {
|
||||
content: ' => ';
|
||||
}
|
||||
ul.jsondiffpatch-textdiff {
|
||||
padding: 0;
|
||||
}
|
||||
.jsondiffpatch-textdiff-location {
|
||||
color: var(--jsdiff-color_fg_location);
|
||||
display: inline-block;
|
||||
min-width: 60px;
|
||||
}
|
||||
.jsondiffpatch-textdiff-line {
|
||||
display: inline-block;
|
||||
}
|
||||
.jsondiffpatch-textdiff-line-number:after {
|
||||
content: ',';
|
||||
}
|
||||
.jsondiffpatch-error {
|
||||
background: red;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue