Skip to content

Commit ddf3200

Browse files
committed
feat(docs-infra): add file explorer tree to the playground editor
replaced tabs with mat-tree to support nesting files under folders in the future. resolves angular#52659 issue
1 parent 57184d0 commit ddf3200

File tree

3 files changed

+271
-144
lines changed

3 files changed

+271
-144
lines changed

adev/src/app/editor/code-editor/code-editor.component.html

Lines changed: 133 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,146 @@
1-
<!-- Code Editor Tabs -->
2-
<div class="docs-code-editor-tabs">
3-
<div class="adev-tabs-and-plus">
4-
<mat-tab-group animationDuration="0ms" mat-stretch-tabs="false">
5-
<!--
6-
Hint: we would like to keep only one instance of #codeEditorWrapper,
7-
that's why we're not placing this element as content of mat-tab, just to
8-
not call another time init method from CodeMirrorEditor service.
9-
-->
10-
@for (file of files(); track file) {
11-
<mat-tab #tab>
12-
<ng-template mat-tab-label>
13-
@if (tab.isActive && isRenamingFile()) {
14-
<form
15-
(submit)="renameFile($event, file.filename)"
16-
(docsClickOutside)="closeRenameFile()"
17-
>
18-
<input
19-
name="rename-file"
20-
class="adev-rename-file-input"
21-
#renameFileInput
22-
(keydown)="$event.stopPropagation()"
23-
/>
24-
</form>
25-
} @else if (restrictedMode()) {
26-
{{ file.filename.replace('src/app/', '') }}
27-
} @else {
28-
{{ file.filename.replace('src/', '') }}
29-
}
1+
<!-- Sidebar -->
2+
<div class="activity-bar-container">
3+
<div class="activity-bar">
4+
<button
5+
(click)="onToggleExplorer()"
6+
[ngClass]="{'active': isExplorerExpanded()}"
7+
type="button"
8+
aria-label="Toggle source code pane"
9+
matTooltip="Toggle source code pane"
10+
matTooltipPosition="above"
11+
>
12+
<docs-icon class="active" [ngClass]="{'active': isExplorerExpanded()}"> folder </docs-icon>
13+
</button>
3014

31-
@if (tab.isActive && canRenameFile(file.filename)) {
15+
<button
16+
type="button"
17+
aria-label="Open current code in editor in an online editor"
18+
[cdkMenuTriggerFor]="launcherMenu"
19+
>
20+
<docs-icon>launch</docs-icon>
21+
</button>
22+
23+
<!-- launcher dropdown window -->
24+
<ng-template #launcherMenu>
25+
<div class="adev-editor-splitview-button" cdkMenu>
26+
<button cdkMenuItem (click)="openCurrentSolutionInFirebaseStudio()">
27+
<span>Open in Firebase Studio </span>
28+
<img
29+
class="icon"
30+
src="assets/images/tutorials/common/firebase-studio_logo.svg"
31+
height="32"
32+
/>
33+
</button>
34+
<button cdkMenuItem (click)="openCurrentCodeInStackBlitz()">Open in StackBlitz</button>
35+
</div>
36+
</ng-template>
37+
<button
38+
type="button"
39+
(click)="downloadCurrentCodeEditorState()"
40+
aria-label="Download current source code"
41+
matTooltip="Download current source code"
42+
matTooltipPosition="above"
43+
>
44+
<docs-icon>download</docs-icon>
45+
</button>
46+
</div>
47+
48+
<as-split direction="horizontal" restrictMove="true" gutterSize="5">
49+
@if (isExplorerExpanded()) {
50+
<as-split-area class="adev-left-side" size="30">
51+
<div class="explorer">
52+
<div class="explorer-header">
53+
@if (canCreateFile()) {
3254
<button
33-
class="docs-rename-file"
34-
aria-label="rename file"
35-
matTooltip="Rename file"
55+
class="adev-add-file"
56+
(click)="onAddButtonClick()"
57+
aria-label="Add a new file"
58+
matTooltip="Add a new file"
3659
matTooltipPosition="above"
37-
(click)="onRenameButtonClick()"
3860
>
39-
<docs-icon>edit</docs-icon>
61+
<docs-icon>add</docs-icon>
4062
</button>
4163
}
42-
@if (tab.isActive && canDeleteFile(file.filename)) {
43-
<button
44-
class="docs-delete-file"
45-
aria-label="Delete file"
46-
matTooltip="Delete file"
47-
matTooltipPosition="above"
48-
(click)="deleteFile(file.filename)"
49-
>
50-
<docs-icon>delete</docs-icon>
51-
</button>
64+
</div>
65+
<div class="explorer-body">
66+
@if (isCreatingFile()) {
67+
<form (submit)="createFile($event)" class="explorer-item-wrapper">
68+
<docs-icon class="file-icon">draft</docs-icon>
69+
<input
70+
name="new-file"
71+
class="adev-new-file-input"
72+
#createFileInput
73+
(blur)="onDiscardFile()"
74+
(keydown)="$event.stopPropagation()"
75+
/>
76+
</form>
5277
}
53-
</ng-template>
54-
</mat-tab>
55-
}
56-
@if (isCreatingFile()) {
57-
<mat-tab>
58-
<ng-template mat-tab-label>
59-
<form (submit)="createFile($event)">
60-
<input
61-
name="new-file"
62-
class="adev-new-file-input"
63-
#createFileInput
64-
(keydown)="$event.stopPropagation()"
65-
/>
66-
</form>
67-
</ng-template>
68-
</mat-tab>
69-
}
70-
</mat-tab-group>
78+
<mat-tree #tree [childrenAccessor]="childrenAccessor" [dataSource]="fileTree()">
79+
<mat-tree-node
80+
class="explorer-item-wrapper"
81+
[ngClass]="{'explorer-selected-item': activeFile() === file.name && !isCreatingFile()}"
82+
#treeNode
83+
(click)="onSetActiveFile(file.name)"
84+
*matTreeNodeDef="let file; let index = $index"
85+
matTreeNodeMinHeight="10"
86+
>
87+
<docs-icon class="file-icon">draft</docs-icon>
7188

72-
@if (canCreateFile()) {
73-
<button
74-
class="adev-add-file"
75-
(click)="onAddButtonClick()"
76-
aria-label="Add a new file"
77-
matTooltip="Add a new file"
78-
matTooltipPosition="above"
79-
>
80-
<docs-icon>add</docs-icon>
81-
</button>
89+
<div class="explorer-item">
90+
@if (activeFile() === file.name && isRenamingFile()) {
91+
<form
92+
(submit)="renameFile($event, file.name)"
93+
(docsClickOutside)="closeRenameFile()"
94+
>
95+
<input
96+
name="rename-file"
97+
class="adev-rename-file-input"
98+
#renameFileInput
99+
(keydown)="$event.stopPropagation()"
100+
/>
101+
</form>
102+
} @else if (restrictedMode()) {
103+
{{ file.name.replace('src/app/', '') }}
104+
} @else {
105+
{{ file.name.replace('src/', '') }}
106+
}
107+
<div class="explorer-item-actions">
108+
@if (activeFile() === file.name && canRenameFile(file.name)) {
109+
<button
110+
class="docs-rename-file"
111+
aria-label="rename file"
112+
matTooltip="Rename file"
113+
matTooltipPosition="above"
114+
(click)="onRenameButtonClick()"
115+
>
116+
<docs-icon>edit</docs-icon>
117+
</button>
118+
}
119+
@if (activeFile() === file.name && canDeleteFile(file.name)) {
120+
<button
121+
class="docs-delete-file"
122+
aria-label="Delete file"
123+
matTooltip="Delete file"
124+
matTooltipPosition="above"
125+
(click)="deleteFile(file.name)"
126+
>
127+
<docs-icon>delete</docs-icon>
128+
</button>
129+
}
130+
</div>
131+
</div>
132+
</mat-tree-node>
133+
</mat-tree>
134+
</div>
135+
</div>
136+
</as-split-area>
82137
}
83-
</div>
84-
85-
<button
86-
class="adev-editor-download-button"
87-
type="button"
88-
aria-label="Open current code in editor in an online editor"
89-
[cdkMenuTriggerFor]="launcherMenu"
90-
>
91-
<docs-icon>launch</docs-icon>
92-
</button>
93-
<!-- launcher dropdown window -->
94-
<ng-template #launcherMenu>
95-
<div class="adev-editor-dropdown" cdkMenu>
96-
<button cdkMenuItem (click)="openCurrentSolutionInFirebaseStudio()">
97-
<span>Open in Firebase Studio </span>
98-
<img class="icon" src="assets/images/tutorials/common/firebase-studio_logo.svg" height="32" />
99-
</button>
100-
<button cdkMenuItem (click)="openCurrentCodeInStackBlitz()">Open in StackBlitz</button>
101-
</div>
102-
</ng-template>
103-
<button
104-
class="adev-editor-download-button"
105-
type="button"
106-
(click)="downloadCurrentCodeEditorState()"
107-
aria-label="Download current source code"
108-
matTooltip="Download current source code"
109-
matTooltipPosition="above"
110-
>
111-
<docs-icon>download</docs-icon>
112-
</button>
138+
<as-split-area class="adev-right-side" [size]="70">
139+
<!-- Code Editor -->
140+
<div #codeEditorWrapper class="adev-code-editor-wrapper"></div>
141+
</as-split-area>
142+
</as-split>
113143
</div>
114-
<!-- Code Editor -->
115-
<div #codeEditorWrapper class="adev-code-editor-wrapper"></div>
116144

117145
@if (displayErrorsBox()) {
118146
<div class="adev-inline-errors-box">

0 commit comments

Comments
 (0)