docyard 1.0.2 → 1.1.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -1
- data/lib/docyard/build/asset_bundler.rb +7 -33
- data/lib/docyard/build/file_copier.rb +7 -15
- data/lib/docyard/build/llms_txt_generator.rb +0 -2
- data/lib/docyard/build/sitemap_generator.rb +1 -1
- data/lib/docyard/build/static_generator.rb +30 -32
- data/lib/docyard/build/step_runner.rb +88 -0
- data/lib/docyard/build/validator.rb +98 -0
- data/lib/docyard/builder.rb +82 -55
- data/lib/docyard/cli.rb +36 -4
- data/lib/docyard/components/aliases.rb +0 -4
- data/lib/docyard/components/processors/callout_processor.rb +1 -1
- data/lib/docyard/components/processors/code_block_diff_preprocessor.rb +1 -1
- data/lib/docyard/components/processors/code_block_focus_preprocessor.rb +1 -1
- data/lib/docyard/components/processors/code_block_options_preprocessor.rb +2 -2
- data/lib/docyard/components/processors/code_group_processor.rb +1 -1
- data/lib/docyard/components/processors/icon_processor.rb +2 -2
- data/lib/docyard/components/processors/tabs_processor.rb +1 -1
- data/lib/docyard/config/schema/definition.rb +29 -0
- data/lib/docyard/config/schema/sections.rb +63 -0
- data/lib/docyard/config/schema/simple_sections.rb +78 -0
- data/lib/docyard/config/schema.rb +28 -31
- data/lib/docyard/config/type_validators.rb +121 -0
- data/lib/docyard/config/validator.rb +136 -61
- data/lib/docyard/config.rb +1 -13
- data/lib/docyard/diagnostic.rb +89 -0
- data/lib/docyard/diagnostic_context.rb +48 -0
- data/lib/docyard/doctor/code_block_checker.rb +136 -0
- data/lib/docyard/doctor/component_checker.rb +49 -0
- data/lib/docyard/doctor/component_checkers/abbreviation_checker.rb +74 -0
- data/lib/docyard/doctor/component_checkers/badge_checker.rb +71 -0
- data/lib/docyard/doctor/component_checkers/base.rb +111 -0
- data/lib/docyard/doctor/component_checkers/callout_checker.rb +34 -0
- data/lib/docyard/doctor/component_checkers/cards_checker.rb +57 -0
- data/lib/docyard/doctor/component_checkers/code_group_checker.rb +47 -0
- data/lib/docyard/doctor/component_checkers/details_checker.rb +51 -0
- data/lib/docyard/doctor/component_checkers/icon_checker.rb +36 -0
- data/lib/docyard/doctor/component_checkers/image_attrs_checker.rb +46 -0
- data/lib/docyard/doctor/component_checkers/space_after_colons_checker.rb +45 -0
- data/lib/docyard/doctor/component_checkers/steps_checker.rb +35 -0
- data/lib/docyard/doctor/component_checkers/tabs_checker.rb +35 -0
- data/lib/docyard/doctor/component_checkers/tooltip_checker.rb +67 -0
- data/lib/docyard/doctor/component_checkers/unknown_type_checker.rb +34 -0
- data/lib/docyard/doctor/config_checker.rb +19 -0
- data/lib/docyard/doctor/config_fixer.rb +87 -0
- data/lib/docyard/doctor/content_checker.rb +164 -0
- data/lib/docyard/doctor/file_scanner.rb +113 -0
- data/lib/docyard/doctor/image_checker.rb +103 -0
- data/lib/docyard/doctor/link_checker.rb +91 -0
- data/lib/docyard/doctor/markdown_fixer.rb +62 -0
- data/lib/docyard/doctor/orphan_checker.rb +82 -0
- data/lib/docyard/doctor/reporter.rb +152 -0
- data/lib/docyard/doctor/sidebar_checker.rb +127 -0
- data/lib/docyard/doctor/sidebar_fixer.rb +47 -0
- data/lib/docyard/doctor.rb +178 -0
- data/lib/docyard/editor_launcher.rb +119 -0
- data/lib/docyard/errors.rb +0 -49
- data/lib/docyard/initializer.rb +32 -39
- data/lib/docyard/navigation/sidebar/local_config_loader.rb +44 -21
- data/lib/docyard/rendering/icon_helpers.rb +1 -3
- data/lib/docyard/search/build_indexer.rb +39 -24
- data/lib/docyard/search/dev_indexer.rb +9 -23
- data/lib/docyard/server/dev_server.rb +55 -13
- data/lib/docyard/server/error_overlay.rb +73 -0
- data/lib/docyard/server/file_watcher.rb +0 -1
- data/lib/docyard/server/page_diagnostics.rb +27 -0
- data/lib/docyard/server/preview_server.rb +17 -13
- data/lib/docyard/server/rack_application.rb +64 -3
- data/lib/docyard/server/resolution_result.rb +0 -4
- data/lib/docyard/templates/assets/css/error-overlay.css +669 -0
- data/lib/docyard/templates/assets/css/variables.css +1 -1
- data/lib/docyard/templates/assets/fonts/Inter-Variable.woff2 +0 -0
- data/lib/docyard/templates/assets/js/components/relative-time.js +42 -0
- data/lib/docyard/templates/assets/js/error-overlay.js +547 -0
- data/lib/docyard/templates/assets/js/hot-reload.js +35 -7
- data/lib/docyard/templates/errors/404.html.erb +1 -1
- data/lib/docyard/templates/errors/500.html.erb +1 -1
- data/lib/docyard/templates/partials/_head.html.erb +1 -1
- data/lib/docyard/templates/partials/_page_actions.html.erb +1 -1
- data/lib/docyard/ui.rb +80 -0
- data/lib/docyard/utils/logging.rb +5 -1
- data/lib/docyard/utils/text_formatter.rb +0 -6
- data/lib/docyard/version.rb +1 -1
- data/lib/docyard.rb +4 -0
- metadata +47 -25
- data/lib/docyard/config/key_validator.rb +0 -30
- data/lib/docyard/config/validation_helpers.rb +0 -83
- data/lib/docyard/config/validators/navigation.rb +0 -43
- data/lib/docyard/config/validators/section.rb +0 -114
- data/lib/docyard/templates/assets/fonts/Inter-Variable.ttf +0 -0
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
var container = document.getElementById('docyard-error-overlay');
|
|
3
|
+
if (!container) return;
|
|
4
|
+
|
|
5
|
+
var diagnostics = JSON.parse(container.dataset.diagnostics);
|
|
6
|
+
var currentFile = container.dataset.currentFile;
|
|
7
|
+
var errorCount = parseInt(container.dataset.errorCount, 10);
|
|
8
|
+
var warningCount = parseInt(container.dataset.warningCount, 10);
|
|
9
|
+
var globalCount = parseInt(container.dataset.globalCount, 10);
|
|
10
|
+
var pageCount = parseInt(container.dataset.pageCount, 10);
|
|
11
|
+
var ssePort = container.dataset.ssePort;
|
|
12
|
+
var editorAvailable = container.dataset.editorAvailable === 'true';
|
|
13
|
+
|
|
14
|
+
var GLOBAL_CATEGORIES = ['CONFIG', 'SIDEBAR', 'ORPHAN'];
|
|
15
|
+
var CATEGORY_LABELS = {
|
|
16
|
+
CONFIG: 'Configuration',
|
|
17
|
+
SIDEBAR: 'Sidebar',
|
|
18
|
+
CONTENT: 'Content',
|
|
19
|
+
COMPONENT: 'Components',
|
|
20
|
+
LINK: 'Broken links',
|
|
21
|
+
IMAGE: 'Missing images',
|
|
22
|
+
SYNTAX: 'Syntax',
|
|
23
|
+
ORPHAN: 'Orphan pages'
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
var STORAGE_KEY = 'docyard-error-overlay';
|
|
27
|
+
|
|
28
|
+
function getStoredState() {
|
|
29
|
+
try {
|
|
30
|
+
var stored = sessionStorage.getItem(STORAGE_KEY);
|
|
31
|
+
return stored ? JSON.parse(stored) : null;
|
|
32
|
+
} catch (e) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function storeState(dismissed, totalCount) {
|
|
38
|
+
try {
|
|
39
|
+
sessionStorage.setItem(STORAGE_KEY, JSON.stringify({
|
|
40
|
+
dismissed: dismissed,
|
|
41
|
+
lastTotalCount: totalCount
|
|
42
|
+
}));
|
|
43
|
+
} catch (e) {
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function shouldStartExpanded() {
|
|
48
|
+
var stored = getStoredState();
|
|
49
|
+
if (!stored || !stored.dismissed) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
var currentTotal = errorCount + warningCount;
|
|
53
|
+
var storedTotal = stored.lastTotalCount || 0;
|
|
54
|
+
if (currentTotal < storedTotal) {
|
|
55
|
+
storeState(true, currentTotal);
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return currentTotal > storedTotal;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
var state = {
|
|
62
|
+
expanded: shouldStartExpanded(),
|
|
63
|
+
activeTab: pageCount > 0 ? 'page' : 'global'
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
function init() {
|
|
67
|
+
render();
|
|
68
|
+
setupEventListeners();
|
|
69
|
+
setupSSE();
|
|
70
|
+
if (state.expanded) {
|
|
71
|
+
document.body.style.overflow = 'hidden';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function render() {
|
|
76
|
+
var html = renderBackdrop() + renderSheet() + renderToast();
|
|
77
|
+
container.innerHTML = html;
|
|
78
|
+
requestAnimationFrame(function () {
|
|
79
|
+
updateTabIndicator();
|
|
80
|
+
var indicator = container.querySelector('.docyard-error-tabs__indicator');
|
|
81
|
+
if (indicator) {
|
|
82
|
+
requestAnimationFrame(function () {
|
|
83
|
+
indicator.classList.add('is-ready');
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function renderBackdrop() {
|
|
90
|
+
return '<div class="docyard-error-backdrop' + (state.expanded ? ' is-visible' : '') + '"></div>';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function renderSheet() {
|
|
94
|
+
return [
|
|
95
|
+
'<div class="docyard-error-sheet' + (state.expanded ? ' is-expanded' : '') + '">',
|
|
96
|
+
'<div class="docyard-error-sheet__drag-handle"></div>',
|
|
97
|
+
renderHeader(),
|
|
98
|
+
renderTabs(),
|
|
99
|
+
renderContent(),
|
|
100
|
+
renderFooter(),
|
|
101
|
+
'</div>'
|
|
102
|
+
].join('');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function renderHeader() {
|
|
106
|
+
return [
|
|
107
|
+
'<div class="docyard-error-sheet__header">',
|
|
108
|
+
'<div class="docyard-error-sheet__counts">',
|
|
109
|
+
errorCount > 0 ? '<span class="docyard-error-sheet__count has-errors"><i class="ph ph-siren"></i>' + errorCount + ' error' + (errorCount !== 1 ? 's' : '') + '</span>' : '',
|
|
110
|
+
warningCount > 0 ? '<span class="docyard-error-sheet__count has-warnings"><i class="ph ph-warning"></i>' + warningCount + ' warning' + (warningCount !== 1 ? 's' : '') + '</span>' : '',
|
|
111
|
+
'</div>',
|
|
112
|
+
'<button class="docyard-error-sheet__close" data-action="dismiss"><i class="ph ph-x"></i></button>',
|
|
113
|
+
'</div>'
|
|
114
|
+
].join('');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function renderTabs() {
|
|
118
|
+
var total = diagnostics.length;
|
|
119
|
+
return [
|
|
120
|
+
'<div class="docyard-error-tabs">',
|
|
121
|
+
'<button class="docyard-error-tabs__tab' + (state.activeTab === 'global' ? ' is-active' : '') + '" data-tab="global">Global<span class="docyard-error-tabs__tab-count">' + globalCount + '</span></button>',
|
|
122
|
+
'<button class="docyard-error-tabs__tab' + (state.activeTab === 'page' ? ' is-active' : '') + '" data-tab="page">This page<span class="docyard-error-tabs__tab-count">' + pageCount + '</span></button>',
|
|
123
|
+
'<button class="docyard-error-tabs__tab' + (state.activeTab === 'all' ? ' is-active' : '') + '" data-tab="all">All<span class="docyard-error-tabs__tab-count">' + total + '</span></button>',
|
|
124
|
+
'<div class="docyard-error-tabs__indicator"></div>',
|
|
125
|
+
'</div>'
|
|
126
|
+
].join('');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function renderContent() {
|
|
130
|
+
var globalDiags = diagnostics.filter(function (d) { return GLOBAL_CATEGORIES.indexOf(d.category) !== -1; });
|
|
131
|
+
var pageDiags = diagnostics.filter(function (d) { return GLOBAL_CATEGORIES.indexOf(d.category) === -1; });
|
|
132
|
+
|
|
133
|
+
return [
|
|
134
|
+
'<div class="docyard-error-sheet__content">',
|
|
135
|
+
'<div class="docyard-error-section' + (state.activeTab === 'global' ? ' is-active' : '') + '" data-section="global">',
|
|
136
|
+
globalDiags.length > 0 ? renderDiagnosticsList(globalDiags, 'affects all pages') : renderEmpty('No global issues'),
|
|
137
|
+
'</div>',
|
|
138
|
+
'<div class="docyard-error-section' + (state.activeTab === 'page' ? ' is-active' : '') + '" data-section="page">',
|
|
139
|
+
pageDiags.length > 0 ? renderDiagnosticsList(pageDiags, currentFile) : renderEmpty('No issues on this page'),
|
|
140
|
+
'</div>',
|
|
141
|
+
'<div class="docyard-error-section' + (state.activeTab === 'all' ? ' is-active' : '') + '" data-section="all">',
|
|
142
|
+
diagnostics.length > 0 ? renderDiagnosticsList(diagnostics, null) : renderEmpty('No issues'),
|
|
143
|
+
'</div>',
|
|
144
|
+
'</div>'
|
|
145
|
+
].join('');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function renderDiagnosticsList(diags, scope) {
|
|
149
|
+
var grouped = groupByCategory(diags);
|
|
150
|
+
var html = [];
|
|
151
|
+
|
|
152
|
+
Object.keys(grouped).forEach(function (category) {
|
|
153
|
+
var items = grouped[category];
|
|
154
|
+
var label = CATEGORY_LABELS[category] || category;
|
|
155
|
+
var scopeText = scope ? ' - ' + scope : '';
|
|
156
|
+
|
|
157
|
+
html.push('<div class="docyard-error-section__header">' + label + '<span class="docyard-error-section__scope">' + scopeText + '</span></div>');
|
|
158
|
+
|
|
159
|
+
items.forEach(function (diag) {
|
|
160
|
+
html.push(renderDiagnosticItem(diag));
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return html.join('');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function groupByCategory(diags) {
|
|
168
|
+
var groups = {};
|
|
169
|
+
diags.forEach(function (d) {
|
|
170
|
+
if (!groups[d.category]) groups[d.category] = [];
|
|
171
|
+
groups[d.category].push(d);
|
|
172
|
+
});
|
|
173
|
+
return groups;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function renderDiagnosticItem(diag) {
|
|
177
|
+
var icon = diag.severity === 'error' ? 'ph-siren' : 'ph-warning';
|
|
178
|
+
var severityClass = diag.severity === 'error' ? 'is-error' : 'is-warning';
|
|
179
|
+
var location = diag.file ? (diag.line ? diag.file + ':' + diag.line : diag.file) : (diag.field || '');
|
|
180
|
+
|
|
181
|
+
var html = [
|
|
182
|
+
'<div class="docyard-error-item">',
|
|
183
|
+
'<div class="docyard-error-item__header">',
|
|
184
|
+
'<i class="ph ' + icon + ' docyard-error-item__indicator ' + severityClass + '"></i>',
|
|
185
|
+
'<div class="docyard-error-item__info">',
|
|
186
|
+
'<div class="docyard-error-item__title">' + escapeHtml(diag.message) + '</div>',
|
|
187
|
+
'<div class="docyard-error-item__meta">'
|
|
188
|
+
];
|
|
189
|
+
|
|
190
|
+
if (location) {
|
|
191
|
+
html.push('<a href="#" class="docyard-error-item__location" data-action="open" data-file="' + escapeAttr(diag.file || '') + '" data-line="' + (diag.line || 1) + '">' + escapeHtml(location) + '</a>');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (diag.doc_url) {
|
|
195
|
+
html.push('<a href="' + escapeAttr(diag.doc_url) + '" class="docyard-error-item__doc-link" target="_blank"><i class="ph ph-book-open"></i>Docs</a>');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
html.push('</div></div>');
|
|
199
|
+
|
|
200
|
+
if (editorAvailable && diag.file) {
|
|
201
|
+
html.push('<div class="docyard-error-item__actions">');
|
|
202
|
+
html.push('<button class="docyard-error-item__action" data-action="open" data-file="' + escapeAttr(diag.file) + '" data-line="' + (diag.line || 1) + '"><i class="ph ph-app-window"></i>Open in editor</button>');
|
|
203
|
+
html.push('</div>');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
html.push('</div>');
|
|
207
|
+
|
|
208
|
+
if (diag.source_context && diag.source_context.length > 0) {
|
|
209
|
+
html.push(renderCodeFrame(diag));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
html.push('</div>');
|
|
213
|
+
|
|
214
|
+
return html.join('');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function renderCodeFrame(diag) {
|
|
218
|
+
var lines = diag.source_context.map(function (ctx) {
|
|
219
|
+
var highlightClass = ctx.highlighted ? ' is-highlighted' : '';
|
|
220
|
+
return [
|
|
221
|
+
'<div class="docyard-error-code-frame__line' + highlightClass + '">',
|
|
222
|
+
'<span class="docyard-error-code-frame__line-number">' + ctx.line + '</span>',
|
|
223
|
+
'<span class="docyard-error-code-frame__line-content">' + escapeHtml(ctx.content) + '</span>',
|
|
224
|
+
'</div>'
|
|
225
|
+
].join('');
|
|
226
|
+
}).join('');
|
|
227
|
+
|
|
228
|
+
return [
|
|
229
|
+
'<div class="docyard-error-code-frame">',
|
|
230
|
+
'<div class="docyard-error-code-frame__header">' + escapeHtml(diag.file) + '</div>',
|
|
231
|
+
'<div class="docyard-error-code-frame__lines">',
|
|
232
|
+
lines,
|
|
233
|
+
'</div>',
|
|
234
|
+
'</div>'
|
|
235
|
+
].join('');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function renderEmpty(message) {
|
|
239
|
+
return '<div class="docyard-error-empty">' + message + '</div>';
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function renderFooter() {
|
|
243
|
+
return [
|
|
244
|
+
'<div class="docyard-error-sheet__footer">',
|
|
245
|
+
'<span class="docyard-error-sheet__hint">Press <kbd>Esc</kbd> to dismiss</span>',
|
|
246
|
+
'</div>'
|
|
247
|
+
].join('');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function renderToast() {
|
|
251
|
+
var html = [
|
|
252
|
+
'<div class="docyard-error-toast' + (!state.expanded ? ' is-visible' : '') + '" data-action="expand">',
|
|
253
|
+
'<div class="docyard-error-toast__content">'
|
|
254
|
+
];
|
|
255
|
+
|
|
256
|
+
if (errorCount > 0) {
|
|
257
|
+
html.push('<span class="docyard-error-toast__item has-errors"><i class="ph ph-siren"></i><span class="docyard-error-toast__count">' + errorCount + '</span><span class="docyard-error-toast__label"> error' + (errorCount !== 1 ? 's' : '') + '</span></span>');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (errorCount > 0 && warningCount > 0) {
|
|
261
|
+
html.push('<span class="docyard-error-toast__separator">|</span>');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (warningCount > 0) {
|
|
265
|
+
html.push('<span class="docyard-error-toast__item has-warnings"><i class="ph ph-warning"></i><span class="docyard-error-toast__count">' + warningCount + '</span><span class="docyard-error-toast__label"> warning' + (warningCount !== 1 ? 's' : '') + '</span></span>');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
html.push('</div>');
|
|
269
|
+
html.push('<span class="docyard-error-toast__hint">Click to view</span>');
|
|
270
|
+
html.push('</div>');
|
|
271
|
+
|
|
272
|
+
return html.join('');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function setupEventListeners() {
|
|
276
|
+
container.addEventListener('click', function (e) {
|
|
277
|
+
var target = e.target.closest('[data-action]');
|
|
278
|
+
if (!target) {
|
|
279
|
+
if (e.target.classList.contains('docyard-error-backdrop')) {
|
|
280
|
+
dismiss();
|
|
281
|
+
}
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
var action = target.dataset.action;
|
|
286
|
+
|
|
287
|
+
if (action === 'dismiss') {
|
|
288
|
+
dismiss();
|
|
289
|
+
} else if (action === 'expand') {
|
|
290
|
+
expand();
|
|
291
|
+
} else if (action === 'open') {
|
|
292
|
+
e.preventDefault();
|
|
293
|
+
openInEditor(target.dataset.file, target.dataset.line);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
container.addEventListener('click', function (e) {
|
|
298
|
+
var tab = e.target.closest('[data-tab]');
|
|
299
|
+
if (!tab) return;
|
|
300
|
+
|
|
301
|
+
var prevTab = state.activeTab;
|
|
302
|
+
var newTab = tab.dataset.tab;
|
|
303
|
+
if (prevTab === newTab) return;
|
|
304
|
+
|
|
305
|
+
var tabs = ['global', 'page', 'all'];
|
|
306
|
+
var prevIndex = tabs.indexOf(prevTab);
|
|
307
|
+
var newIndex = tabs.indexOf(newTab);
|
|
308
|
+
var direction = newIndex > prevIndex ? 'right' : 'left';
|
|
309
|
+
|
|
310
|
+
state.activeTab = newTab;
|
|
311
|
+
|
|
312
|
+
container.querySelectorAll('.docyard-error-tabs__tab').forEach(function (t) {
|
|
313
|
+
t.classList.toggle('is-active', t.dataset.tab === newTab);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
container.querySelectorAll('.docyard-error-section').forEach(function (section) {
|
|
317
|
+
var isActive = section.dataset.section === newTab;
|
|
318
|
+
section.classList.toggle('is-active', isActive);
|
|
319
|
+
if (isActive) {
|
|
320
|
+
section.dataset.direction = direction;
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
updateTabIndicator();
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
document.addEventListener('keydown', function (e) {
|
|
328
|
+
if (e.key === 'Escape' && state.expanded) {
|
|
329
|
+
dismiss();
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
setupTouchHandling();
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function setupTouchHandling() {
|
|
337
|
+
var startY = 0;
|
|
338
|
+
var currentY = 0;
|
|
339
|
+
var isDragging = false;
|
|
340
|
+
var sheet = null;
|
|
341
|
+
|
|
342
|
+
container.addEventListener('touchstart', function (e) {
|
|
343
|
+
var handle = e.target.closest('.docyard-error-sheet__drag-handle');
|
|
344
|
+
if (!handle) return;
|
|
345
|
+
|
|
346
|
+
sheet = container.querySelector('.docyard-error-sheet');
|
|
347
|
+
if (!sheet || !state.expanded) return;
|
|
348
|
+
|
|
349
|
+
isDragging = true;
|
|
350
|
+
startY = e.touches[0].clientY;
|
|
351
|
+
currentY = startY;
|
|
352
|
+
sheet.style.transition = 'none';
|
|
353
|
+
}, { passive: true });
|
|
354
|
+
|
|
355
|
+
document.addEventListener('touchmove', function (e) {
|
|
356
|
+
if (!isDragging || !sheet) return;
|
|
357
|
+
|
|
358
|
+
currentY = e.touches[0].clientY;
|
|
359
|
+
var deltaY = currentY - startY;
|
|
360
|
+
|
|
361
|
+
if (deltaY > 0) {
|
|
362
|
+
sheet.style.transform = 'translateY(' + deltaY + 'px)';
|
|
363
|
+
}
|
|
364
|
+
}, { passive: true });
|
|
365
|
+
|
|
366
|
+
document.addEventListener('touchend', function () {
|
|
367
|
+
if (!isDragging || !sheet) return;
|
|
368
|
+
|
|
369
|
+
var deltaY = currentY - startY;
|
|
370
|
+
sheet.style.transition = '';
|
|
371
|
+
sheet.style.transform = '';
|
|
372
|
+
|
|
373
|
+
if (deltaY > 80) {
|
|
374
|
+
dismiss();
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
isDragging = false;
|
|
378
|
+
sheet = null;
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function updateTabIndicator() {
|
|
383
|
+
var activeTab = container.querySelector('.docyard-error-tabs__tab.is-active');
|
|
384
|
+
var indicator = container.querySelector('.docyard-error-tabs__indicator');
|
|
385
|
+
if (!activeTab || !indicator) return;
|
|
386
|
+
|
|
387
|
+
var tabsContainer = container.querySelector('.docyard-error-tabs');
|
|
388
|
+
var containerRect = tabsContainer.getBoundingClientRect();
|
|
389
|
+
var tabRect = activeTab.getBoundingClientRect();
|
|
390
|
+
|
|
391
|
+
indicator.style.width = tabRect.width + 'px';
|
|
392
|
+
indicator.style.transform = 'translateX(' + (tabRect.left - containerRect.left) + 'px)';
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function dismiss() {
|
|
396
|
+
state.expanded = false;
|
|
397
|
+
document.body.style.overflow = '';
|
|
398
|
+
storeState(true, errorCount + warningCount);
|
|
399
|
+
|
|
400
|
+
var sheet = container.querySelector('.docyard-error-sheet');
|
|
401
|
+
var backdrop = container.querySelector('.docyard-error-backdrop');
|
|
402
|
+
var toast = container.querySelector('.docyard-error-toast');
|
|
403
|
+
|
|
404
|
+
if (sheet) {
|
|
405
|
+
sheet.classList.add('is-dismissing');
|
|
406
|
+
sheet.classList.remove('is-expanded');
|
|
407
|
+
}
|
|
408
|
+
if (backdrop) backdrop.classList.remove('is-visible');
|
|
409
|
+
|
|
410
|
+
setTimeout(function () {
|
|
411
|
+
if (toast) toast.classList.add('is-visible');
|
|
412
|
+
if (sheet) sheet.classList.remove('is-dismissing');
|
|
413
|
+
}, 150);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function expand() {
|
|
417
|
+
state.expanded = true;
|
|
418
|
+
document.body.style.overflow = 'hidden';
|
|
419
|
+
storeState(false, errorCount + warningCount);
|
|
420
|
+
|
|
421
|
+
var sheet = container.querySelector('.docyard-error-sheet');
|
|
422
|
+
var backdrop = container.querySelector('.docyard-error-backdrop');
|
|
423
|
+
var toast = container.querySelector('.docyard-error-toast');
|
|
424
|
+
|
|
425
|
+
if (toast) toast.classList.remove('is-visible');
|
|
426
|
+
|
|
427
|
+
setTimeout(function () {
|
|
428
|
+
if (sheet) sheet.classList.add('is-expanded');
|
|
429
|
+
if (backdrop) backdrop.classList.add('is-visible');
|
|
430
|
+
}, 50);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function openInEditor(file, line) {
|
|
434
|
+
if (!editorAvailable) return;
|
|
435
|
+
|
|
436
|
+
fetch('/__docyard/open-in-editor?file=' + encodeURIComponent(file) + '&line=' + (line || 1))
|
|
437
|
+
.catch(function (err) {
|
|
438
|
+
console.error('[Docyard] Failed to open editor:', err);
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function setupSSE() {
|
|
443
|
+
if (!ssePort) return;
|
|
444
|
+
|
|
445
|
+
var url = 'http://127.0.0.1:' + ssePort + '/';
|
|
446
|
+
var eventSource = new EventSource(url);
|
|
447
|
+
|
|
448
|
+
eventSource.addEventListener('diagnostics', function (event) {
|
|
449
|
+
var data = JSON.parse(event.data);
|
|
450
|
+
if (data.global) {
|
|
451
|
+
updateGlobalDiagnostics(data.global);
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
eventSource.onerror = function () {
|
|
456
|
+
eventSource.close();
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function updateGlobalDiagnostics(globalDiags) {
|
|
461
|
+
var pageDiags = diagnostics.filter(function(d) {
|
|
462
|
+
return GLOBAL_CATEGORIES.indexOf(d.category) === -1;
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
var prevTotal = errorCount + warningCount;
|
|
466
|
+
|
|
467
|
+
diagnostics = globalDiags.concat(pageDiags);
|
|
468
|
+
errorCount = diagnostics.filter(function(d) { return d.severity === 'error'; }).length;
|
|
469
|
+
warningCount = diagnostics.filter(function(d) { return d.severity === 'warning'; }).length;
|
|
470
|
+
globalCount = globalDiags.length;
|
|
471
|
+
pageCount = pageDiags.length;
|
|
472
|
+
|
|
473
|
+
container.dataset.diagnostics = JSON.stringify(diagnostics);
|
|
474
|
+
container.dataset.errorCount = errorCount;
|
|
475
|
+
container.dataset.warningCount = warningCount;
|
|
476
|
+
container.dataset.globalCount = globalCount;
|
|
477
|
+
container.dataset.pageCount = pageCount;
|
|
478
|
+
|
|
479
|
+
var currentTotal = errorCount + warningCount;
|
|
480
|
+
if (!state.expanded && currentTotal > prevTotal) {
|
|
481
|
+
state.expanded = true;
|
|
482
|
+
storeState(false, currentTotal);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
render();
|
|
486
|
+
|
|
487
|
+
if (state.expanded) {
|
|
488
|
+
document.body.style.overflow = 'hidden';
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function escapeHtml(str) {
|
|
493
|
+
if (!str) return '';
|
|
494
|
+
return String(str)
|
|
495
|
+
.replace(/&/g, '&')
|
|
496
|
+
.replace(/</g, '<')
|
|
497
|
+
.replace(/>/g, '>')
|
|
498
|
+
.replace(/"/g, '"');
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function escapeAttr(str) {
|
|
502
|
+
if (!str) return '';
|
|
503
|
+
return String(str)
|
|
504
|
+
.replace(/&/g, '&')
|
|
505
|
+
.replace(/"/g, '"');
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function updateFromDataset(dataset) {
|
|
509
|
+
var prevTotal = errorCount + warningCount;
|
|
510
|
+
|
|
511
|
+
diagnostics = JSON.parse(dataset.diagnostics);
|
|
512
|
+
currentFile = dataset.currentFile;
|
|
513
|
+
errorCount = parseInt(dataset.errorCount, 10);
|
|
514
|
+
warningCount = parseInt(dataset.warningCount, 10);
|
|
515
|
+
globalCount = parseInt(dataset.globalCount, 10);
|
|
516
|
+
pageCount = parseInt(dataset.pageCount, 10);
|
|
517
|
+
|
|
518
|
+
container.dataset.diagnostics = dataset.diagnostics;
|
|
519
|
+
container.dataset.currentFile = dataset.currentFile;
|
|
520
|
+
container.dataset.errorCount = dataset.errorCount;
|
|
521
|
+
container.dataset.warningCount = dataset.warningCount;
|
|
522
|
+
container.dataset.globalCount = dataset.globalCount;
|
|
523
|
+
container.dataset.pageCount = dataset.pageCount;
|
|
524
|
+
|
|
525
|
+
if (pageCount > 0 && state.activeTab === 'global') {
|
|
526
|
+
state.activeTab = 'page';
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
var currentTotal = errorCount + warningCount;
|
|
530
|
+
if (!state.expanded && currentTotal > prevTotal) {
|
|
531
|
+
state.expanded = true;
|
|
532
|
+
storeState(false, currentTotal);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
render();
|
|
536
|
+
|
|
537
|
+
if (state.expanded) {
|
|
538
|
+
document.body.style.overflow = 'hidden';
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
window.docyardErrorOverlay = {
|
|
543
|
+
update: updateFromDataset
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
init();
|
|
547
|
+
})();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
(function() {
|
|
1
|
+
(function () {
|
|
2
2
|
var ssePort = window.__DOCYARD_SSE_PORT__;
|
|
3
3
|
if (!ssePort) return;
|
|
4
4
|
|
|
5
5
|
var url = 'http://127.0.0.1:' + ssePort + '/';
|
|
6
6
|
var eventSource = new EventSource(url);
|
|
7
7
|
|
|
8
|
-
eventSource.addEventListener('reload', function(event) {
|
|
8
|
+
eventSource.addEventListener('reload', function (event) {
|
|
9
9
|
var data = JSON.parse(event.data);
|
|
10
10
|
if (data.type === 'content') {
|
|
11
11
|
console.log('[Docyard] Content updated');
|
|
@@ -16,14 +16,16 @@
|
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
eventSource.onerror = function() {
|
|
19
|
+
eventSource.onerror = function () {
|
|
20
20
|
eventSource.close();
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
function reloadContent() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
var cacheBuster = '_dc=' + Date.now();
|
|
25
|
+
var separator = location.href.indexOf('?') === -1 ? '?' : '&';
|
|
26
|
+
fetch(location.href + separator + cacheBuster)
|
|
27
|
+
.then(function (response) { return response.text(); })
|
|
28
|
+
.then(function (html) {
|
|
27
29
|
var parser = new DOMParser();
|
|
28
30
|
var newDoc = parser.parseFromString(html, 'text/html');
|
|
29
31
|
var newContent = newDoc.querySelector('.content');
|
|
@@ -33,12 +35,38 @@
|
|
|
33
35
|
currentContent.innerHTML = newContent.innerHTML;
|
|
34
36
|
if (window.Prism) window.Prism.highlightAll();
|
|
35
37
|
if (window.docyardTOC) window.docyardTOC.init();
|
|
38
|
+
updateErrorOverlay(newDoc);
|
|
36
39
|
} else {
|
|
37
40
|
location.reload();
|
|
38
41
|
}
|
|
39
42
|
})
|
|
40
|
-
.catch(function() {
|
|
43
|
+
.catch(function () {
|
|
41
44
|
location.reload();
|
|
42
45
|
});
|
|
43
46
|
}
|
|
47
|
+
|
|
48
|
+
function updateErrorOverlay(newDoc) {
|
|
49
|
+
var newOverlay = newDoc.getElementById('docyard-error-overlay');
|
|
50
|
+
var currentOverlay = document.getElementById('docyard-error-overlay');
|
|
51
|
+
|
|
52
|
+
var newData = newOverlay ? newOverlay.dataset : null;
|
|
53
|
+
var currentData = currentOverlay ? currentOverlay.dataset : null;
|
|
54
|
+
|
|
55
|
+
var changed = diagnosticsChanged(newData, currentData);
|
|
56
|
+
if (!changed) return;
|
|
57
|
+
|
|
58
|
+
if (newOverlay && window.docyardErrorOverlay && window.docyardErrorOverlay.update) {
|
|
59
|
+
window.docyardErrorOverlay.update(newOverlay.dataset);
|
|
60
|
+
} else {
|
|
61
|
+
location.reload();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function diagnosticsChanged(newData, currentData) {
|
|
66
|
+
if (!newData && !currentData) return false;
|
|
67
|
+
if (!newData || !currentData) return true;
|
|
68
|
+
return newData.errorCount !== currentData.errorCount ||
|
|
69
|
+
newData.warningCount !== currentData.warningCount ||
|
|
70
|
+
newData.diagnostics !== currentData.diagnostics;
|
|
71
|
+
}
|
|
44
72
|
})();
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<style>
|
|
8
8
|
@font-face {
|
|
9
9
|
font-family: 'Inter';
|
|
10
|
-
src: url('<%= base_url %>_docyard/fonts/Inter-Variable.
|
|
10
|
+
src: url('<%= base_url %>_docyard/fonts/Inter-Variable.woff2') format('woff2');
|
|
11
11
|
font-weight: 100 900;
|
|
12
12
|
font-style: normal;
|
|
13
13
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<style>
|
|
8
8
|
@font-face {
|
|
9
9
|
font-family: 'Inter';
|
|
10
|
-
src: url('<%= base_url %>_docyard/fonts/Inter-Variable.
|
|
10
|
+
src: url('<%= base_url %>_docyard/fonts/Inter-Variable.woff2') format('woff2');
|
|
11
11
|
font-weight: 100 900;
|
|
12
12
|
font-style: normal;
|
|
13
13
|
}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<% end %>
|
|
33
33
|
<% end %>
|
|
34
34
|
|
|
35
|
-
<link rel="preload" href="<%= asset_path('_docyard/fonts/Inter-Variable.
|
|
35
|
+
<link rel="preload" href="<%= asset_path('_docyard/fonts/Inter-Variable.woff2') %>" as="font" type="font/woff2" crossorigin>
|
|
36
36
|
|
|
37
37
|
<%= render_partial('_icon_library') %>
|
|
38
38
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<% end %>
|
|
15
15
|
<% if @show_last_updated && @last_updated %>
|
|
16
16
|
<div class="page-actions__last-updated">
|
|
17
|
-
Last updated <time datetime="<%= @last_updated[:iso] %>" title="<%= @last_updated[:formatted] %>"><%= @last_updated[:
|
|
17
|
+
Last updated <time datetime="<%= @last_updated[:iso] %>" title="<%= @last_updated[:formatted] %>"><%= @last_updated[:formatted_short] %></time>
|
|
18
18
|
</div>
|
|
19
19
|
<% end %>
|
|
20
20
|
</div>
|