@eui/base 21.0.0-alpha.8 → 21.0.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/changelog.html +785 -7627
- package/docs/classes/ConsoleAppender.html +18 -0
- package/docs/classes/EuiEuLanguages.html +18 -0
- package/docs/classes/EuiLazyService.html +18 -0
- package/docs/classes/EuiPagination.html +18 -0
- package/docs/classes/EuiService.html +18 -0
- package/docs/classes/LogAppender.html +18 -0
- package/docs/classes/Logger.html +18 -0
- package/docs/classes/LoggerMock.html +18 -0
- package/docs/classes/UrlAppender.html +18 -0
- package/docs/classes/UxBadgeLegacy.html +18 -0
- package/docs/classes/UxClearErrorFeedbackEvent.html +18 -0
- package/docs/classes/UxErrorGroupOnClickEvent.html +18 -0
- package/docs/classes/UxErrorOutput.html +18 -0
- package/docs/classes/UxLinkLegacy.html +18 -0
- package/docs/classes/UxPublishErrorFeedbackEvent.html +18 -0
- package/docs/classes/UxValidationErrorClass.html +18 -0
- package/docs/dependencies.html +18 -0
- package/docs/index.html +20 -2
- package/docs/interfaces/ApiQueue.html +18 -0
- package/docs/interfaces/ApiQueueItem.html +18 -0
- package/docs/interfaces/AppState.html +18 -0
- package/docs/interfaces/ConnectionStatus.html +18 -0
- package/docs/interfaces/ConsoleAppenderConfig.html +18 -0
- package/docs/interfaces/ConsoleAppenderTypeConfig.html +18 -0
- package/docs/interfaces/CoreState.html +18 -0
- package/docs/interfaces/EnvDynamicConfig.html +18 -0
- package/docs/interfaces/EuiAppHandlersConfig.html +18 -0
- package/docs/interfaces/EuiAppJsonConfig.html +18 -0
- package/docs/interfaces/EuiAuthConfig.html +18 -0
- package/docs/interfaces/EuiConfig.html +18 -0
- package/docs/interfaces/EuiEnvConfig.html +18 -0
- package/docs/interfaces/EuiGlobalConfig.html +18 -0
- package/docs/interfaces/EuiGrowlMessage.html +18 -0
- package/docs/interfaces/EuiLanguage.html +18 -0
- package/docs/interfaces/EuiMenuItem.html +153 -0
- package/docs/interfaces/EuiPaginationConfig.html +18 -0
- package/docs/interfaces/EuiServiceModel.html +18 -0
- package/docs/interfaces/EuiServiceStatus.html +18 -0
- package/docs/interfaces/EuiStoreServiceModel.html +18 -0
- package/docs/interfaces/EuiUserRight.html +18 -0
- package/docs/interfaces/GlobalConfig.html +18 -0
- package/docs/interfaces/HttpErrorHandlerConfig.html +18 -0
- package/docs/interfaces/HttpErrorRouteConfig.html +18 -0
- package/docs/interfaces/I18nConfig.html +18 -0
- package/docs/interfaces/I18nLoaderConfig.html +24 -3
- package/docs/interfaces/I18nResource.html +18 -0
- package/docs/interfaces/I18nServiceConfig.html +18 -0
- package/docs/interfaces/I18nState.html +18 -0
- package/docs/interfaces/LoadedConfigModules.html +18 -0
- package/docs/interfaces/LocaleServiceConfig.html +18 -0
- package/docs/interfaces/LocaleState.html +18 -0
- package/docs/interfaces/LogAppenderConfig.html +18 -0
- package/docs/interfaces/LogAppenderTypeConfig.html +18 -0
- package/docs/interfaces/LogConfig.html +18 -0
- package/docs/interfaces/LogEvent.html +18 -0
- package/docs/interfaces/LogPosition.html +18 -0
- package/docs/interfaces/ModuleConfig.html +18 -0
- package/docs/interfaces/ModulesConfig.html +18 -0
- package/docs/interfaces/NotificationsState.html +18 -0
- package/docs/interfaces/UrlAppenderConfig.html +18 -0
- package/docs/interfaces/UrlAppenderTypeConfig.html +18 -0
- package/docs/interfaces/UrlLogEvent.html +18 -0
- package/docs/interfaces/UserConfig.html +18 -0
- package/docs/interfaces/UserDetails.html +18 -0
- package/docs/interfaces/UserPreferences.html +18 -0
- package/docs/interfaces/UserState.html +18 -0
- package/docs/interfaces/UxErrorFeedback.html +18 -0
- package/docs/interfaces/UxErrorFollowMap.html +18 -0
- package/docs/interfaces/UxErrorInfo.html +18 -0
- package/docs/interfaces/UxErrorMessage.html +18 -0
- package/docs/interfaces/UxFormValidationError.html +18 -0
- package/docs/interfaces/UxHttpErrorInfo.html +18 -0
- package/docs/interfaces/UxHttpErrorResponse.html +18 -0
- package/docs/interfaces/UxModalLegacy.html +18 -0
- package/docs/interfaces/UxValidationErrorAttribute.html +18 -0
- package/docs/interfaces/UxValidationErrorFeedback.html +18 -0
- package/docs/interfaces/UxValidationErrorI18nMessage.html +18 -0
- package/docs/interfaces/VersionsConfig.html +18 -0
- package/docs/interfaces/XHRConfig.html +18 -0
- package/docs/js/libs/bootstrap-native.js +1 -1
- package/docs/js/libs/jszip.min.js +13 -0
- package/docs/js/libs/svg-pan-zoom.min.js +3 -3
- package/docs/js/libs/tablesort.min.js +3 -3
- package/docs/js/libs/tablesort.number.min.js +3 -3
- package/docs/js/menu-wc.js +16 -20
- package/docs/js/menu-wc_es5.js +1 -1
- package/docs/js/routes/routes_index.js +1 -0
- package/docs/js/routes.js +15 -8
- package/docs/js/search/search_index.js +2 -2
- package/docs/license.html +20 -2
- package/docs/miscellaneous/enumerations.html +18 -0
- package/docs/miscellaneous/functions.html +18 -0
- package/docs/miscellaneous/typealiases.html +18 -0
- package/docs/miscellaneous/variables.html +44 -0
- package/docs/modules.html +18 -0
- package/docs/overview.html +28 -0
- package/docs/properties.html +19 -1
- package/docs/routes.html +204 -0
- package/docs/template-playground/default-templates.json +192 -0
- package/docs/template-playground/hbs-render.service.ts +212 -0
- package/docs/template-playground/main.ts +9 -0
- package/docs/template-playground/template-editor.service.ts +173 -0
- package/docs/template-playground/template-playground.component.ts +614 -0
- package/docs/template-playground/template-playground.module.ts +29 -0
- package/docs/template-playground/zip-export.service.ts +86 -0
- package/docs/template-playground-app/app.js +1389 -0
- package/docs/template-playground-app/index.html +462 -0
- package/package.json +35 -36
- package/{index.d.ts → types/eui-base.d.ts} +4 -1
- package/types/eui-base.d.ts.map +1 -0
- package/index.d.ts.map +0 -1
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
import { Component, OnInit, ViewChild, ElementRef, OnDestroy } from '@angular/core';
|
|
2
|
+
import { HttpClient } from '@angular/common/http';
|
|
3
|
+
import { TemplateEditorService } from './template-editor.service';
|
|
4
|
+
import { ZipExportService } from './zip-export.service';
|
|
5
|
+
import { HbsRenderService } from './hbs-render.service';
|
|
6
|
+
|
|
7
|
+
interface Template {
|
|
8
|
+
name: string;
|
|
9
|
+
path: string;
|
|
10
|
+
type: 'template' | 'partial';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface Session {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
success: boolean;
|
|
16
|
+
message: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface CompoDocConfig {
|
|
20
|
+
hideGenerator?: boolean;
|
|
21
|
+
disableSourceCode?: boolean;
|
|
22
|
+
disableGraph?: boolean;
|
|
23
|
+
disableCoverage?: boolean;
|
|
24
|
+
disablePrivate?: boolean;
|
|
25
|
+
disableProtected?: boolean;
|
|
26
|
+
disableInternal?: boolean;
|
|
27
|
+
disableLifeCycleHooks?: boolean;
|
|
28
|
+
disableConstructors?: boolean;
|
|
29
|
+
disableRoutesGraph?: boolean;
|
|
30
|
+
disableSearch?: boolean;
|
|
31
|
+
disableDependencies?: boolean;
|
|
32
|
+
disableProperties?: boolean;
|
|
33
|
+
disableDomTree?: boolean;
|
|
34
|
+
disableTemplateTab?: boolean;
|
|
35
|
+
disableStyleTab?: boolean;
|
|
36
|
+
disableMainGraph?: boolean;
|
|
37
|
+
disableFilePath?: boolean;
|
|
38
|
+
disableOverview?: boolean;
|
|
39
|
+
hideDarkModeToggle?: boolean;
|
|
40
|
+
minimal?: boolean;
|
|
41
|
+
customFavicon?: string;
|
|
42
|
+
includes?: string;
|
|
43
|
+
includesName?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@Component({
|
|
47
|
+
selector: 'template-playground-root',
|
|
48
|
+
template: `
|
|
49
|
+
<div class="template-playground">
|
|
50
|
+
<div class="template-playground-header">
|
|
51
|
+
<h2>Template Playground</h2>
|
|
52
|
+
<div class="template-playground-status">
|
|
53
|
+
<span *ngIf="sessionId" class="session-info">Session: {{sessionId.substring(0, 8)}}...</span>
|
|
54
|
+
<span *ngIf="saving" class="saving-indicator">Saving...</span>
|
|
55
|
+
<span *ngIf="lastSaved" class="last-saved">Last saved: {{lastSaved | date:'short'}}</span>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="template-playground-actions">
|
|
58
|
+
<button class="btn btn-secondary" (click)="toggleConfigPanel()">⚙️ Config</button>
|
|
59
|
+
<button class="btn btn-primary" (click)="resetToDefault()">Reset to Default</button>
|
|
60
|
+
<button class="btn btn-success" (click)="exportZip()">Download Templates</button>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<!-- Configuration Panel -->
|
|
65
|
+
<div class="config-panel" [class.collapsed]="!showConfigPanel">
|
|
66
|
+
<h3>CompoDoc Configuration</h3>
|
|
67
|
+
<div class="config-options">
|
|
68
|
+
<label><input type="checkbox" [(ngModel)]="config.hideGenerator" (change)="updateConfig()"> Hide Generator</label>
|
|
69
|
+
<label><input type="checkbox" [(ngModel)]="config.hideDarkModeToggle" (change)="updateConfig()"> Hide Dark Mode Toggle</label>
|
|
70
|
+
<label><input type="checkbox" [(ngModel)]="config.minimal" (change)="updateConfig()"> Minimal Mode</label>
|
|
71
|
+
<label><input type="checkbox" [(ngModel)]="config.disableOverview" (change)="updateConfig()"> Disable Overview</label>
|
|
72
|
+
<label><input type="checkbox" [(ngModel)]="config.disableFilePath" (change)="updateConfig()"> Disable File Path</label>
|
|
73
|
+
<label><input type="checkbox" [(ngModel)]="config.disableSourceCode" (change)="updateConfig()"> Disable Source Code</label>
|
|
74
|
+
<label><input type="checkbox" [(ngModel)]="config.disableGraph" (change)="updateConfig()"> Disable Graph</label>
|
|
75
|
+
<label><input type="checkbox" [(ngModel)]="config.disableMainGraph" (change)="updateConfig()"> Disable Main Graph</label>
|
|
76
|
+
<label><input type="checkbox" [(ngModel)]="config.disableRoutesGraph" (change)="updateConfig()"> Disable Routes Graph</label>
|
|
77
|
+
<label><input type="checkbox" [(ngModel)]="config.disableCoverage" (change)="updateConfig()"> Disable Coverage</label>
|
|
78
|
+
<label><input type="checkbox" [(ngModel)]="config.disableSearch" (change)="updateConfig()"> Disable Search</label>
|
|
79
|
+
<label><input type="checkbox" [(ngModel)]="config.disableDependencies" (change)="updateConfig()"> Disable Dependencies</label>
|
|
80
|
+
<label><input type="checkbox" [(ngModel)]="config.disablePrivate" (change)="updateConfig()"> Disable Private</label>
|
|
81
|
+
<label><input type="checkbox" [(ngModel)]="config.disableProtected" (change)="updateConfig()"> Disable Protected</label>
|
|
82
|
+
<label><input type="checkbox" [(ngModel)]="config.disableInternal" (change)="updateConfig()"> Disable Internal</label>
|
|
83
|
+
<label><input type="checkbox" [(ngModel)]="config.disableLifeCycleHooks" (change)="updateConfig()"> Disable Lifecycle Hooks</label>
|
|
84
|
+
<label><input type="checkbox" [(ngModel)]="config.disableConstructors" (change)="updateConfig()"> Disable Constructors</label>
|
|
85
|
+
<label><input type="checkbox" [(ngModel)]="config.disableProperties" (change)="updateConfig()"> Disable Properties</label>
|
|
86
|
+
<label><input type="checkbox" [(ngModel)]="config.disableDomTree" (change)="updateConfig()"> Disable DOM Tree</label>
|
|
87
|
+
<label><input type="checkbox" [(ngModel)]="config.disableTemplateTab" (change)="updateConfig()"> Disable Template Tab</label>
|
|
88
|
+
<label><input type="checkbox" [(ngModel)]="config.disableStyleTab" (change)="updateConfig()"> Disable Style Tab</label>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<div class="template-playground-body">
|
|
93
|
+
<div class="template-playground-sidebar">
|
|
94
|
+
<div class="template-file-list">
|
|
95
|
+
<h3>Templates</h3>
|
|
96
|
+
<ul class="file-list">
|
|
97
|
+
<li *ngFor="let template of templates; trackBy: trackByName"
|
|
98
|
+
[class.active]="selectedFile === template"
|
|
99
|
+
(click)="selectFile(template)">
|
|
100
|
+
<i class="file-icon ion-document-text"></i>
|
|
101
|
+
{{template.name}}
|
|
102
|
+
<span class="file-type">{{template.type}}</span>
|
|
103
|
+
</li>
|
|
104
|
+
</ul>
|
|
105
|
+
|
|
106
|
+
<div *ngIf="templates.length === 0" class="loading-templates">
|
|
107
|
+
Loading templates...
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<div class="template-playground-main">
|
|
113
|
+
<div class="template-playground-editor">
|
|
114
|
+
<div class="editor-header" *ngIf="selectedFile">
|
|
115
|
+
<h4>{{selectedFile.path}}</h4>
|
|
116
|
+
<span class="file-type-badge">{{selectedFile.type}}</span>
|
|
117
|
+
</div>
|
|
118
|
+
<div #editorContainer class="editor-container"></div>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<div class="template-playground-preview">
|
|
122
|
+
<div class="preview-header">
|
|
123
|
+
<h4>Live Preview</h4>
|
|
124
|
+
<button class="btn btn-sm btn-secondary" (click)="refreshPreview()">🔄 Refresh</button>
|
|
125
|
+
</div>
|
|
126
|
+
<iframe #previewFrame class="preview-frame" [src]="previewUrl"></iframe>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
`,
|
|
132
|
+
styles: [`
|
|
133
|
+
.template-playground {
|
|
134
|
+
display: flex;
|
|
135
|
+
flex-direction: column;
|
|
136
|
+
height: 100vh;
|
|
137
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.template-playground-header {
|
|
141
|
+
display: flex;
|
|
142
|
+
justify-content: space-between;
|
|
143
|
+
align-items: center;
|
|
144
|
+
padding: 1rem 2rem;
|
|
145
|
+
background: #f8f9fa;
|
|
146
|
+
border-bottom: 1px solid #dee2e6;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.template-playground-status {
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
gap: 1rem;
|
|
153
|
+
font-size: 0.875rem;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.session-info {
|
|
157
|
+
color: #6c757d;
|
|
158
|
+
font-family: monospace;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.saving-indicator {
|
|
162
|
+
color: #ffc107;
|
|
163
|
+
font-weight: bold;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.last-saved {
|
|
167
|
+
color: #28a745;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.template-playground-actions {
|
|
171
|
+
display: flex;
|
|
172
|
+
gap: 0.5rem;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.config-panel {
|
|
176
|
+
background: #e9ecef;
|
|
177
|
+
padding: 1rem 2rem;
|
|
178
|
+
border-bottom: 1px solid #dee2e6;
|
|
179
|
+
transition: all 0.3s ease;
|
|
180
|
+
max-height: 200px;
|
|
181
|
+
overflow: hidden;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.config-panel.collapsed {
|
|
185
|
+
max-height: 0;
|
|
186
|
+
padding: 0 2rem;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.config-options {
|
|
190
|
+
display: grid;
|
|
191
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
192
|
+
gap: 0.5rem;
|
|
193
|
+
margin-top: 0.5rem;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.config-options label {
|
|
197
|
+
display: flex;
|
|
198
|
+
align-items: center;
|
|
199
|
+
gap: 0.5rem;
|
|
200
|
+
font-size: 0.875rem;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.template-playground-body {
|
|
204
|
+
display: flex;
|
|
205
|
+
flex: 1;
|
|
206
|
+
overflow: hidden;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.template-playground-sidebar {
|
|
210
|
+
width: 250px;
|
|
211
|
+
background: #f8f9fa;
|
|
212
|
+
border-right: 1px solid #dee2e6;
|
|
213
|
+
overflow-y: auto;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.template-file-list {
|
|
217
|
+
padding: 1rem;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.template-file-list h3 {
|
|
221
|
+
margin: 0 0 0.5rem 0;
|
|
222
|
+
font-size: 0.875rem;
|
|
223
|
+
font-weight: 600;
|
|
224
|
+
color: #495057;
|
|
225
|
+
text-transform: uppercase;
|
|
226
|
+
letter-spacing: 0.5px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.file-list {
|
|
230
|
+
list-style: none;
|
|
231
|
+
padding: 0;
|
|
232
|
+
margin: 0 0 1.5rem 0;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.file-list li {
|
|
236
|
+
display: flex;
|
|
237
|
+
align-items: center;
|
|
238
|
+
padding: 0.5rem;
|
|
239
|
+
cursor: pointer;
|
|
240
|
+
border-radius: 4px;
|
|
241
|
+
font-size: 0.875rem;
|
|
242
|
+
transition: background-color 0.15s ease;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.file-list li:hover {
|
|
246
|
+
background: #e9ecef;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.file-list li.active {
|
|
250
|
+
background: #007bff;
|
|
251
|
+
color: white;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.file-icon {
|
|
255
|
+
margin-right: 0.5rem;
|
|
256
|
+
opacity: 0.7;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.file-type {
|
|
260
|
+
margin-left: auto;
|
|
261
|
+
font-size: 0.75rem;
|
|
262
|
+
opacity: 0.7;
|
|
263
|
+
text-transform: uppercase;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.loading-templates {
|
|
267
|
+
text-align: center;
|
|
268
|
+
color: #6c757d;
|
|
269
|
+
font-style: italic;
|
|
270
|
+
padding: 2rem;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.template-playground-main {
|
|
274
|
+
flex: 1;
|
|
275
|
+
display: flex;
|
|
276
|
+
overflow: hidden;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.template-playground-editor {
|
|
280
|
+
width: 50%;
|
|
281
|
+
display: flex;
|
|
282
|
+
flex-direction: column;
|
|
283
|
+
border-right: 1px solid #dee2e6;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.editor-header {
|
|
287
|
+
display: flex;
|
|
288
|
+
justify-content: space-between;
|
|
289
|
+
align-items: center;
|
|
290
|
+
padding: 0.75rem 1rem;
|
|
291
|
+
background: #f8f9fa;
|
|
292
|
+
border-bottom: 1px solid #dee2e6;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.editor-header h4 {
|
|
296
|
+
margin: 0;
|
|
297
|
+
font-size: 0.875rem;
|
|
298
|
+
font-weight: 600;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.file-type-badge {
|
|
302
|
+
background: #6c757d;
|
|
303
|
+
color: white;
|
|
304
|
+
padding: 0.125rem 0.5rem;
|
|
305
|
+
border-radius: 12px;
|
|
306
|
+
font-size: 0.75rem;
|
|
307
|
+
text-transform: uppercase;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.editor-container {
|
|
311
|
+
flex: 1;
|
|
312
|
+
position: relative;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.template-playground-preview {
|
|
316
|
+
width: 50%;
|
|
317
|
+
display: flex;
|
|
318
|
+
flex-direction: column;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.preview-header {
|
|
322
|
+
display: flex;
|
|
323
|
+
justify-content: space-between;
|
|
324
|
+
align-items: center;
|
|
325
|
+
padding: 0.75rem 1rem;
|
|
326
|
+
background: #f8f9fa;
|
|
327
|
+
border-bottom: 1px solid #dee2e6;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.preview-header h4 {
|
|
331
|
+
margin: 0;
|
|
332
|
+
font-size: 0.875rem;
|
|
333
|
+
font-weight: 600;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.preview-frame {
|
|
337
|
+
flex: 1;
|
|
338
|
+
border: none;
|
|
339
|
+
background: white;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.btn {
|
|
343
|
+
padding: 0.375rem 0.75rem;
|
|
344
|
+
border: 1px solid transparent;
|
|
345
|
+
border-radius: 0.25rem;
|
|
346
|
+
font-size: 0.875rem;
|
|
347
|
+
font-weight: 500;
|
|
348
|
+
text-decoration: none;
|
|
349
|
+
cursor: pointer;
|
|
350
|
+
transition: all 0.15s ease;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.btn-primary {
|
|
354
|
+
background: #007bff;
|
|
355
|
+
border-color: #007bff;
|
|
356
|
+
color: white;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.btn-primary:hover {
|
|
360
|
+
background: #0056b3;
|
|
361
|
+
border-color: #004085;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.btn-secondary {
|
|
365
|
+
background: #6c757d;
|
|
366
|
+
border-color: #6c757d;
|
|
367
|
+
color: white;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.btn-secondary:hover {
|
|
371
|
+
background: #545b62;
|
|
372
|
+
border-color: #4e555b;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.btn-success {
|
|
376
|
+
background: #28a745;
|
|
377
|
+
border-color: #28a745;
|
|
378
|
+
color: white;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.btn-success:hover {
|
|
382
|
+
background: #1e7e34;
|
|
383
|
+
border-color: #1c7430;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.btn-sm {
|
|
387
|
+
padding: 0.25rem 0.5rem;
|
|
388
|
+
font-size: 0.75rem;
|
|
389
|
+
}
|
|
390
|
+
`]
|
|
391
|
+
})
|
|
392
|
+
export class TemplatePlaygroundComponent implements OnInit, OnDestroy {
|
|
393
|
+
@ViewChild('editorContainer', { static: true }) editorContainer!: ElementRef;
|
|
394
|
+
@ViewChild('previewFrame', { static: true }) previewFrame!: ElementRef;
|
|
395
|
+
|
|
396
|
+
sessionId: string = '';
|
|
397
|
+
templates: Template[] = [];
|
|
398
|
+
selectedFile: Template | null = null;
|
|
399
|
+
config: CompoDocConfig = {};
|
|
400
|
+
showConfigPanel: boolean = false;
|
|
401
|
+
saving: boolean = false;
|
|
402
|
+
lastSaved: Date | null = null;
|
|
403
|
+
|
|
404
|
+
private saveTimeout?: number;
|
|
405
|
+
private readonly SAVE_DELAY = 300; // 300ms debounce
|
|
406
|
+
|
|
407
|
+
get previewUrl(): string {
|
|
408
|
+
return this.sessionId ? `/api/session/${this.sessionId}/docs/` : '';
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
constructor(
|
|
412
|
+
private http: HttpClient,
|
|
413
|
+
private editorService: TemplateEditorService,
|
|
414
|
+
private zipService: ZipExportService,
|
|
415
|
+
private hbsService: HbsRenderService
|
|
416
|
+
) {}
|
|
417
|
+
|
|
418
|
+
async ngOnInit() {
|
|
419
|
+
try {
|
|
420
|
+
await this.createSession();
|
|
421
|
+
await this.loadSessionTemplates();
|
|
422
|
+
await this.loadSessionConfig();
|
|
423
|
+
this.initializeEditor();
|
|
424
|
+
} catch (error) {
|
|
425
|
+
console.error('Error initializing template playground:', error);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
ngOnDestroy() {
|
|
430
|
+
if (this.saveTimeout) {
|
|
431
|
+
clearTimeout(this.saveTimeout);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
private async createSession(): Promise<void> {
|
|
436
|
+
const response = await this.http.post<Session>('/api/session/create', {}).toPromise();
|
|
437
|
+
if (response && response.success) {
|
|
438
|
+
this.sessionId = response.sessionId;
|
|
439
|
+
console.log('Session created:', this.sessionId);
|
|
440
|
+
} else {
|
|
441
|
+
throw new Error('Failed to create session');
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
private async loadSessionTemplates(): Promise<void> {
|
|
446
|
+
if (!this.sessionId) return;
|
|
447
|
+
|
|
448
|
+
const response = await this.http.get<{templates: Template[], success: boolean}>(`/api/session/${this.sessionId}/templates`).toPromise();
|
|
449
|
+
if (response && response.success) {
|
|
450
|
+
this.templates = response.templates;
|
|
451
|
+
|
|
452
|
+
// Auto-select the first template
|
|
453
|
+
if (this.templates.length > 0 && !this.selectedFile) {
|
|
454
|
+
this.selectFile(this.templates[0]);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
private async loadSessionConfig(): Promise<void> {
|
|
460
|
+
if (!this.sessionId) return;
|
|
461
|
+
|
|
462
|
+
const response = await this.http.get<{config: CompoDocConfig, success: boolean}>(`/api/session/${this.sessionId}/config`).toPromise();
|
|
463
|
+
if (response && response.success) {
|
|
464
|
+
this.config = response.config;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
initializeEditor() {
|
|
469
|
+
this.editorService.initializeEditor(this.editorContainer.nativeElement);
|
|
470
|
+
|
|
471
|
+
// Set up debounced save on content change
|
|
472
|
+
this.editorService.setOnChangeCallback((content: string) => {
|
|
473
|
+
this.scheduleAutoSave(content);
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
async selectFile(template: Template) {
|
|
478
|
+
this.selectedFile = template;
|
|
479
|
+
|
|
480
|
+
if (!this.sessionId) return;
|
|
481
|
+
|
|
482
|
+
try {
|
|
483
|
+
const response = await this.http.get<{content: string, success: boolean}>(`/api/session/${this.sessionId}/template/${template.path}`).toPromise();
|
|
484
|
+
if (response && response.success) {
|
|
485
|
+
this.editorService.setEditorContent(response.content, template.type === 'template' ? 'handlebars' : 'handlebars');
|
|
486
|
+
}
|
|
487
|
+
} catch (error) {
|
|
488
|
+
console.error('Error loading template:', error);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
private scheduleAutoSave(content: string): void {
|
|
493
|
+
if (!this.selectedFile || !this.sessionId) return;
|
|
494
|
+
|
|
495
|
+
// Clear existing timeout
|
|
496
|
+
if (this.saveTimeout) {
|
|
497
|
+
clearTimeout(this.saveTimeout);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Set saving indicator
|
|
501
|
+
this.saving = true;
|
|
502
|
+
|
|
503
|
+
// Schedule new save
|
|
504
|
+
this.saveTimeout = window.setTimeout(async () => {
|
|
505
|
+
try {
|
|
506
|
+
await this.saveTemplate(content);
|
|
507
|
+
this.saving = false;
|
|
508
|
+
this.lastSaved = new Date();
|
|
509
|
+
} catch (error) {
|
|
510
|
+
console.error('Error saving template:', error);
|
|
511
|
+
this.saving = false;
|
|
512
|
+
}
|
|
513
|
+
}, this.SAVE_DELAY);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
private async saveTemplate(content: string): Promise<void> {
|
|
517
|
+
if (!this.selectedFile || !this.sessionId) return;
|
|
518
|
+
|
|
519
|
+
const response = await this.http.post<{success: boolean}>(`/api/session/${this.sessionId}/template/${this.selectedFile.path}`, {
|
|
520
|
+
content
|
|
521
|
+
}).toPromise();
|
|
522
|
+
|
|
523
|
+
if (!response || !response.success) {
|
|
524
|
+
throw new Error('Failed to save template');
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
async updateConfig(): Promise<void> {
|
|
529
|
+
if (!this.sessionId) return;
|
|
530
|
+
|
|
531
|
+
try {
|
|
532
|
+
const response = await this.http.post<{success: boolean}>(`/api/session/${this.sessionId}/config`, {
|
|
533
|
+
config: this.config
|
|
534
|
+
}).toPromise();
|
|
535
|
+
|
|
536
|
+
if (response && response.success) {
|
|
537
|
+
// Config updated, documentation will be regenerated automatically
|
|
538
|
+
}
|
|
539
|
+
} catch (error) {
|
|
540
|
+
console.error('Error updating config:', error);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
toggleConfigPanel(): void {
|
|
545
|
+
this.showConfigPanel = !this.showConfigPanel;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
refreshPreview(): void {
|
|
549
|
+
if (this.previewFrame?.nativeElement) {
|
|
550
|
+
this.previewFrame.nativeElement.src = this.previewFrame.nativeElement.src;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
resetToDefault(): void {
|
|
555
|
+
// Implementation for resetting to default templates
|
|
556
|
+
if (confirm('Are you sure you want to reset all templates to their default values? This action cannot be undone.')) {
|
|
557
|
+
// TODO: Implement reset functionality
|
|
558
|
+
console.log('Reset to default templates');
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
async exportZip(): Promise<void> {
|
|
563
|
+
try {
|
|
564
|
+
if (!this.sessionId) {
|
|
565
|
+
console.error('No active session. Please refresh the page and try again.');
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
console.log('Creating template package...');
|
|
570
|
+
|
|
571
|
+
// Call server-side ZIP creation endpoint for all templates
|
|
572
|
+
const response = await this.http.post(`/api/session/${this.sessionId}/download-all-templates`, {}, {
|
|
573
|
+
responseType: 'blob',
|
|
574
|
+
observe: 'response'
|
|
575
|
+
}).toPromise();
|
|
576
|
+
|
|
577
|
+
if (!response || !response.body) {
|
|
578
|
+
throw new Error('Failed to create template package');
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// Get the ZIP file as a blob
|
|
582
|
+
const zipBlob = response.body;
|
|
583
|
+
|
|
584
|
+
// Get filename from response headers or construct it
|
|
585
|
+
const contentDisposition = response.headers.get('Content-Disposition');
|
|
586
|
+
let filename = `compodoc-templates-${this.sessionId}.zip`;
|
|
587
|
+
|
|
588
|
+
if (contentDisposition) {
|
|
589
|
+
const filenameMatch = contentDisposition.match(/filename="([^"]+)"/);
|
|
590
|
+
if (filenameMatch) {
|
|
591
|
+
filename = filenameMatch[1];
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Create download link and trigger download
|
|
596
|
+
const url = URL.createObjectURL(zipBlob);
|
|
597
|
+
const a = document.createElement('a');
|
|
598
|
+
a.href = url;
|
|
599
|
+
a.download = filename;
|
|
600
|
+
document.body.appendChild(a);
|
|
601
|
+
a.click();
|
|
602
|
+
document.body.removeChild(a);
|
|
603
|
+
URL.revokeObjectURL(url);
|
|
604
|
+
|
|
605
|
+
console.log('Template package downloaded successfully!');
|
|
606
|
+
} catch (error) {
|
|
607
|
+
console.error('Error downloading template package:', error);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
trackByName(index: number, item: Template): string {
|
|
612
|
+
return item.name;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { BrowserModule } from '@angular/platform-browser';
|
|
3
|
+
import { CommonModule } from '@angular/common';
|
|
4
|
+
import { FormsModule } from '@angular/forms';
|
|
5
|
+
import { HttpClientModule } from '@angular/common/http';
|
|
6
|
+
|
|
7
|
+
import { TemplatePlaygroundComponent } from './template-playground.component';
|
|
8
|
+
import { TemplateEditorService } from './template-editor.service';
|
|
9
|
+
import { ZipExportService } from './zip-export.service';
|
|
10
|
+
import { HbsRenderService } from './hbs-render.service';
|
|
11
|
+
|
|
12
|
+
@NgModule({
|
|
13
|
+
declarations: [
|
|
14
|
+
TemplatePlaygroundComponent
|
|
15
|
+
],
|
|
16
|
+
imports: [
|
|
17
|
+
BrowserModule,
|
|
18
|
+
CommonModule,
|
|
19
|
+
FormsModule,
|
|
20
|
+
HttpClientModule
|
|
21
|
+
],
|
|
22
|
+
providers: [
|
|
23
|
+
TemplateEditorService,
|
|
24
|
+
ZipExportService,
|
|
25
|
+
HbsRenderService
|
|
26
|
+
],
|
|
27
|
+
bootstrap: [TemplatePlaygroundComponent]
|
|
28
|
+
})
|
|
29
|
+
export class TemplatePlaygroundModule { }
|