Skip to content

Commit 1427290

Browse files
authored
feat: revamp demo app (#49)
1 parent 48b9802 commit 1427290

File tree

9 files changed

+318
-73
lines changed

9 files changed

+318
-73
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"@angular/compiler": "^21.0.5",
4040
"@angular/core": "^21.0.5",
4141
"@angular/forms": "^21.0.5",
42+
"@angular/material": "^21.0.5",
4243
"@angular/platform-browser": "^21.0.5",
4344
"@angular/platform-browser-dynamic": "^21.0.5",
4445
"@angular/router": "^21.0.5",

pnpm-lock.yaml

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 67 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,69 @@
1-
<h2>ngx-json-treeview</h2>
2-
3-
<h3>Collapsed</h3>
4-
<div class="json-container">
5-
<ngx-json-treeview
6-
[json]="json"
7-
[expanded]="false"
8-
[enableClickableValues]="true" />
9-
</div>
10-
11-
<h3>Max Depth (1)</h3>
12-
<div class="json-container">
13-
<ngx-json-treeview [json]="json" [depth]="1" [enableClickableValues]="true" />
14-
</div>
15-
16-
<h3>Fully Expanded</h3>
17-
<div class="json-container">
18-
<ngx-json-treeview [json]="json" [enableClickableValues]="true" />
19-
</div>
20-
21-
<h3>Clickable Nodes</h3>
22-
<div class="clickable-container">
23-
<div class="json-container">
24-
<h4>Object</h4>
25-
<ngx-json-treeview
26-
[json]="json"
27-
[expanded]="false"
28-
[valueClickHandlers]="clickHandlers"
29-
[enableClickableValues]="true" />
30-
<h4>Primitives</h4>
31-
@for (primitive of primitives; track $index) {
32-
<ngx-json-treeview
33-
[json]="primitive"
34-
[valueClickHandlers]="primitiveClickHandlers"
35-
[enableClickableValues]="true" />
36-
}
37-
</div>
38-
@let segment = currentSegment();
39-
@if (segment) {
1+
<mat-toolbar class="fixed-header">
2+
<span>ngx-json-treeview</span>
3+
<span class="spacer"></span>
4+
<button
5+
mat-icon-button
6+
[matMenuTriggerFor]="themeMenu"
7+
aria-label="Select theme">
8+
<mat-icon>
9+
@switch (themeService.theme()) {
10+
@case ('dark') {
11+
dark_mode
12+
}
13+
@case ('light') {
14+
light_mode
15+
}
16+
@case ('system') {
17+
brightness_auto
18+
}
19+
}
20+
</mat-icon>
21+
</button>
22+
<mat-menu #themeMenu="matMenu">
23+
<button mat-menu-item (click)="themeService.setTheme('light')">
24+
<mat-icon>light_mode</mat-icon>
25+
<span>Light</span>
26+
</button>
27+
<button mat-menu-item (click)="themeService.setTheme('dark')">
28+
<mat-icon>dark_mode</mat-icon>
29+
<span>Dark</span>
30+
</button>
31+
<button mat-menu-item (click)="themeService.setTheme('system')">
32+
<mat-icon>brightness_auto</mat-icon>
33+
<span>System</span>
34+
</button>
35+
</mat-menu>
36+
</mat-toolbar>
37+
<main class="content-container">
38+
<div class="clickable-container">
39+
<div class="json-container">
40+
<button
41+
class="action-button"
42+
mat-icon-button
43+
(click)="toggleExpansion()"
44+
[matTooltip]="expansionDepth() === -1 ? 'Collapse all' : 'Expand all'">
45+
@if (expansionDepth() === -1) {
46+
<mat-icon>collapse_all</mat-icon>
47+
} @else {
48+
<mat-icon>expand_all</mat-icon>
49+
}
50+
</button>
51+
<div class="json-scroll-container">
52+
<ngx-json-treeview
53+
[json]="json"
54+
[expanded]="true"
55+
[depth]="expansionDepth()"
56+
[enableClickableValues]="true"
57+
[valueClickHandlers]="clickHandlers" />
58+
</div>
59+
</div>
60+
@let segment = currentSegment();
4061
<div class="preview-pane">
41-
<pre>{{ stringify(segment.value) }}</pre>
62+
@if (segment) {
63+
<pre>{{ stringify(segment.value) }}</pre>
64+
} @else {
65+
{{ 'Click an attribute to preview it here.' }}
66+
}
4267
</div>
43-
}
44-
</div>
45-
46-
<h3>Simple Types</h3>
47-
<div class="json-container">
48-
@for (primitive of primitives; track $index) {
49-
<ngx-json-treeview [json]="primitive" />
50-
}
51-
</div>
52-
53-
<h3>Arrays</h3>
54-
<div class="json-container">
55-
<ngx-json-treeview [json]="[1, 2, 3, 'hello', 'world']" />
56-
</div>
68+
</div>
69+
</main>
Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,90 @@
1+
.fixed-header {
2+
background: var(--mat-sys-surface);
3+
border-bottom: 1px solid var(--mat-sys-outline-variant);
4+
color: var(--mat-sys-on-surface);
5+
left: 0;
6+
position: fixed;
7+
right: 0;
8+
top: 0;
9+
z-index: 1000;
10+
}
11+
12+
.spacer {
13+
flex: 1 1 auto;
14+
}
15+
16+
.content-container {
17+
box-sizing: border-box;
18+
display: flex;
19+
flex-direction: column;
20+
height: calc(100vh - 64px);
21+
margin-top: 64px; // Toolbar height
22+
overflow: hidden;
23+
padding: 20px;
24+
}
25+
126
.json-container {
2-
font-family: monospace;
27+
background: var(--mat-sys-surface-container-low);
28+
border: 1px solid var(--mat-sys-outline-variant);
29+
border-radius: 4px;
30+
display: flex;
31+
flex: 1;
32+
flex-direction: column;
33+
font-family: 'Roboto Mono', monospace;
334
overflow: hidden;
35+
position: relative;
36+
37+
&:hover .action-button {
38+
opacity: 1;
39+
}
40+
41+
.action-button {
42+
opacity: 0;
43+
position: absolute;
44+
right: 20px;
45+
top: 4px;
46+
transition: opacity 0.2s;
47+
z-index: 10;
48+
}
49+
}
50+
51+
.json-scroll-container {
52+
flex: 1;
53+
overflow: auto;
454
padding: 10px;
555
}
656

757
.clickable-container {
58+
box-sizing: border-box;
859
display: flex;
9-
gap: 10px;
60+
gap: 20px;
61+
height: 100%;
62+
overflow: hidden;
1063
width: 100%;
1164
}
1265

1366
.clickable-container > .json-container,
1467
.clickable-container > .preview-pane {
1568
box-sizing: border-box;
1669
flex-basis: 50%;
70+
height: 100%;
1771
}
1872

1973
.preview-pane {
20-
background: #f9f9f9;
21-
border-left: 1px solid #ccc;
74+
align-items: center;
75+
background: var(--mat-sys-surface-container-low);
76+
border: 1px solid var(--mat-sys-outline-variant);
77+
border-radius: 4px;
78+
color: var(--mat-sys-on-surface-variant);
79+
display: flex;
80+
flex: 1;
81+
justify-content: center;
82+
overflow: auto;
2283
padding: 10px;
84+
85+
pre {
86+
height: 100%;
87+
margin: 0;
88+
width: 100%;
89+
}
2390
}

projects/demo/src/app/app.component.ts

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,37 @@
1-
import { Component, signal } from '@angular/core';
1+
import { Component, inject, signal } from '@angular/core';
2+
import { MatButtonModule } from '@angular/material/button';
3+
import { MatIconModule } from '@angular/material/icon';
4+
import { MatMenuModule } from '@angular/material/menu';
5+
import { MatTabsModule } from '@angular/material/tabs';
6+
import { MatToolbarModule } from '@angular/material/toolbar';
7+
import { MatTooltipModule } from '@angular/material/tooltip';
28
import {
39
NgxJsonTreeviewComponent,
410
Segment,
11+
VALUE_CLICK_HANDLERS,
512
ValueClickHandler,
613
} from 'ngx-json-treeview';
14+
import { ThemeService } from './services/theme.service';
715

816
@Component({
917
selector: 'app-root',
10-
imports: [NgxJsonTreeviewComponent],
18+
imports: [
19+
MatButtonModule,
20+
MatIconModule,
21+
MatMenuModule,
22+
MatTabsModule,
23+
MatToolbarModule,
24+
MatTooltipModule,
25+
NgxJsonTreeviewComponent,
26+
],
1127
templateUrl: './app.component.html',
1228
styleUrl: './app.component.scss',
1329
})
1430
export class AppComponent {
1531
currentSegment = signal<Segment | undefined>(undefined);
32+
expansionDepth = signal(1);
1633

17-
primitives = [13, 'hello, world!', true, null, {}, []];
34+
protected readonly themeService = inject(ThemeService);
1835

1936
baseObj = {
2037
string: 'Hello World',
@@ -50,6 +67,7 @@ export class AppComponent {
5067
};
5168

5269
clickHandlers: ValueClickHandler[] = [
70+
...VALUE_CLICK_HANDLERS,
5371
{
5472
canHandle: (segment: Segment) => {
5573
return ['object', 'array', 'string'].includes(segment.type ?? '');
@@ -60,17 +78,6 @@ export class AppComponent {
6078
},
6179
];
6280

63-
primitiveClickHandlers: ValueClickHandler[] = [
64-
{
65-
canHandle: (segment: Segment) => {
66-
return ['string'].includes(segment.type ?? '');
67-
},
68-
handler: (segment: Segment) => {
69-
this.currentSegment.set(segment);
70-
},
71-
},
72-
];
73-
7481
stringify(obj: any) {
7582
if (typeof obj === 'function') {
7683
return '' + obj;
@@ -79,4 +86,8 @@ export class AppComponent {
7986
}
8087
return JSON.stringify(obj, null, 2);
8188
}
89+
90+
toggleExpansion() {
91+
this.expansionDepth.update((depth) => (depth === -1 ? 0 : -1));
92+
}
8293
}

projects/demo/src/app/app.config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
2+
import { MAT_ICON_DEFAULT_OPTIONS } from '@angular/material/icon';
3+
import { provideAnimations } from '@angular/platform-browser/animations';
24
import { provideRouter } from '@angular/router';
35

46
import { routes } from './app.routes';
@@ -7,5 +9,10 @@ export const appConfig: ApplicationConfig = {
79
providers: [
810
provideZoneChangeDetection({ eventCoalescing: true }),
911
provideRouter(routes),
12+
provideAnimations(),
13+
{
14+
provide: MAT_ICON_DEFAULT_OPTIONS,
15+
useValue: { fontSet: 'material-symbols-rounded' },
16+
},
1017
],
1118
};

0 commit comments

Comments
 (0)