@@ -4,6 +4,10 @@ import "./style.css";
44
55const viewer = document . querySelector ( "json-diff-viewer" ) ;
66const toggle = document . querySelector ( "#theme-toggle" ) ;
7+ const loadToggle = document . querySelector ( "#load-toggle" ) ;
8+ const panel = document . querySelector ( "#input-panel" ) ;
9+ const tabs = document . querySelectorAll ( ".tab" ) ;
10+ const compareBtn = document . querySelector ( "#compare-btn" ) ;
711
812const themes = {
913 dark : {
@@ -41,7 +45,84 @@ toggle.addEventListener("click", () => {
4145 applyTheme ( toggleTheme ( getTheme ( ) ) ) ;
4246} ) ;
4347
48+ const uncheckFilter = ( ) => {
49+ const checkbox = viewer . shadowRoot ?. querySelector ( '[data-action="filter"]' ) ;
50+ if ( ! checkbox ?. checked ) return ;
51+ checkbox . checked = false ;
52+ checkbox . dispatchEvent ( new Event ( "change" ) ) ;
53+ } ;
54+
4455Promise . all ( [
4556 fetch ( `${ import . meta. env . BASE_URL } data/a1.json` ) . then ( ( r ) => r . json ( ) ) ,
4657 fetch ( `${ import . meta. env . BASE_URL } data/a2.json` ) . then ( ( r ) => r . json ( ) ) ,
47- ] ) . then ( ( [ left , right ] ) => viewer . setData ( left , right ) ) ;
58+ ] ) . then ( ( [ left , right ] ) => {
59+ viewer . setData ( left , right ) ;
60+ uncheckFilter ( ) ;
61+ } ) ;
62+
63+ loadToggle . addEventListener ( "click" , ( ) => {
64+ panel . classList . toggle ( "collapsed" ) ;
65+ loadToggle . classList . toggle ( "active" , ! panel . classList . contains ( "collapsed" ) ) ;
66+ } ) ;
67+
68+ for ( const tab of tabs ) {
69+ tab . addEventListener ( "click" , ( ) => {
70+ for ( const t of tabs ) t . classList . remove ( "active" ) ;
71+ tab . classList . add ( "active" ) ;
72+ panel . dataset . mode = tab . dataset . mode ;
73+ } ) ;
74+ }
75+
76+ for ( const btn of panel . querySelectorAll ( ".file-btn" ) ) {
77+ const input = panel . querySelector ( `input[type="file"][data-side="${ btn . dataset . side } "]` ) ;
78+ btn . addEventListener ( "click" , ( ) => input . click ( ) ) ;
79+ input . addEventListener ( "change" , ( ) => {
80+ const name = input . files [ 0 ] ?. name ;
81+ btn . textContent = name || "Choose file..." ;
82+ btn . classList . toggle ( "has-file" , ! ! name ) ;
83+ } ) ;
84+ }
85+
86+ const readFile = ( file ) =>
87+ new Promise ( ( resolve ) => {
88+ const reader = new FileReader ( ) ;
89+ reader . onload = ( e ) => resolve ( JSON . parse ( e . target . result ) ) ;
90+ reader . readAsText ( file ) ;
91+ } ) ;
92+
93+ const getInput = ( side , mode ) => {
94+ const types = { file : 'input[type="file"]' , paste : "textarea" , url : 'input[type="url"]' } ;
95+ return panel . querySelector ( `${ types [ mode ] } [data-side="${ side } "]` ) ;
96+ } ;
97+
98+ const loaders = {
99+ file : ( ) => {
100+ const left = getInput ( "left" , "file" ) . files [ 0 ] ;
101+ const right = getInput ( "right" , "file" ) . files [ 0 ] ;
102+ if ( ! left || ! right ) return ;
103+ return Promise . all ( [ readFile ( left ) , readFile ( right ) ] ) ;
104+ } ,
105+ paste : ( ) => {
106+ const left = getInput ( "left" , "paste" ) . value ;
107+ const right = getInput ( "right" , "paste" ) . value ;
108+ if ( ! left || ! right ) return ;
109+ return Promise . resolve ( [ JSON . parse ( left ) , JSON . parse ( right ) ] ) ;
110+ } ,
111+ url : ( ) => {
112+ const left = getInput ( "left" , "url" ) . value ;
113+ const right = getInput ( "right" , "url" ) . value ;
114+ if ( ! left || ! right ) return ;
115+ return Promise . all ( [
116+ fetch ( left ) . then ( ( r ) => r . json ( ) ) ,
117+ fetch ( right ) . then ( ( r ) => r . json ( ) ) ,
118+ ] ) ;
119+ } ,
120+ } ;
121+
122+ compareBtn . addEventListener ( "click" , async ( ) => {
123+ const result = await loaders [ panel . dataset . mode ] ?. ( ) ;
124+ if ( ! result ) return ;
125+ viewer . setData ( result [ 0 ] , result [ 1 ] ) ;
126+ panel . classList . add ( "collapsed" ) ;
127+ loadToggle . classList . remove ( "active" ) ;
128+ } ) ;
0 commit comments