retold-content-system 1.0.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.
Files changed (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +107 -0
  3. package/build-codejar-bundle.js +29 -0
  4. package/build-codemirror-bundle.js +29 -0
  5. package/codejar-entry.js +10 -0
  6. package/codemirror-entry.js +16 -0
  7. package/content/Dogs.txt.md +2 -0
  8. package/content/README.md +35 -0
  9. package/content/_sidebar.md +3 -0
  10. package/content/_topbar.md +1 -0
  11. package/content/cover.md +12 -0
  12. package/content/getting-started.md +73 -0
  13. package/css/content-system.css +42 -0
  14. package/css/github.css +118 -0
  15. package/docs/.nojekyll +0 -0
  16. package/docs/README.md +24 -0
  17. package/docs/_sidebar.md +16 -0
  18. package/docs/_topbar.md +6 -0
  19. package/docs/cli.md +119 -0
  20. package/docs/cover.md +16 -0
  21. package/docs/css/docuserve.css +73 -0
  22. package/docs/editor-guide.md +137 -0
  23. package/docs/getting-started.md +73 -0
  24. package/docs/index.html +39 -0
  25. package/docs/keyboard-shortcuts.md +40 -0
  26. package/docs/retold-catalog.json +81 -0
  27. package/docs/retold-keyword-index.json +19 -0
  28. package/docs/topics.md +83 -0
  29. package/html/codejar-bundle.js +16 -0
  30. package/html/codemirror-bundle.js +29982 -0
  31. package/html/edit.html +25 -0
  32. package/html/index.html +25 -0
  33. package/html/preview.html +19 -0
  34. package/package.json +70 -0
  35. package/server.js +43 -0
  36. package/source/Pict-Application-ContentEditor-Configuration.json +15 -0
  37. package/source/Pict-Application-ContentEditor.js +1361 -0
  38. package/source/Pict-Application-ContentReader-Configuration.json +15 -0
  39. package/source/Pict-Application-ContentReader.js +91 -0
  40. package/source/Pict-ContentSystem-Bundle.js +21 -0
  41. package/source/cli/ContentSystem-CLI-Program.js +15 -0
  42. package/source/cli/ContentSystem-CLI-Run.js +3 -0
  43. package/source/cli/ContentSystem-Server-Setup.js +405 -0
  44. package/source/cli/commands/ContentSystem-Command-Serve.js +104 -0
  45. package/source/providers/Pict-Provider-ContentEditor.js +198 -0
  46. package/source/views/PictView-Editor-CodeEditor.js +271 -0
  47. package/source/views/PictView-Editor-Layout.js +1194 -0
  48. package/source/views/PictView-Editor-MarkdownEditor.js +115 -0
  49. package/source/views/PictView-Editor-MarkdownReference.js +801 -0
  50. package/source/views/PictView-Editor-SettingsPanel.js +563 -0
  51. package/source/views/PictView-Editor-TopBar.js +366 -0
  52. package/source/views/PictView-Editor-Topics.js +1025 -0
@@ -0,0 +1,366 @@
1
+ const libPictView = require('pict-view');
2
+
3
+ const _ViewConfiguration =
4
+ {
5
+ ViewIdentifier: "ContentEditor-TopBar",
6
+
7
+ DefaultRenderable: "ContentEditor-TopBar-Display",
8
+ DefaultDestinationAddress: "#ContentEditor-TopBar-Container",
9
+
10
+ AutoRender: false,
11
+
12
+ CSS: /*css*/`
13
+ .content-editor-topbar
14
+ {
15
+ display: flex;
16
+ align-items: center;
17
+ background: #3D3229;
18
+ color: #E8E0D4;
19
+ padding: 0;
20
+ height: 48px;
21
+ border-bottom: 3px solid #2E7D74;
22
+ position: relative;
23
+ }
24
+ .content-editor-topbar-brand
25
+ {
26
+ padding: 0 16px;
27
+ font-size: 1rem;
28
+ font-weight: 600;
29
+ color: #E8E0D4;
30
+ white-space: nowrap;
31
+ flex-shrink: 0;
32
+ }
33
+ /* Centered file name — absolutely positioned so it stays
34
+ centered in the full bar regardless of left/right content */
35
+ .content-editor-topbar-file
36
+ {
37
+ position: absolute;
38
+ left: 50%;
39
+ transform: translateX(-50%);
40
+ max-width: 50%;
41
+ text-align: center;
42
+ overflow: hidden;
43
+ text-overflow: ellipsis;
44
+ white-space: nowrap;
45
+ pointer-events: none;
46
+ }
47
+ .content-editor-topbar-filename
48
+ {
49
+ font-size: 0.9rem;
50
+ font-weight: 500;
51
+ color: #E8E0D4;
52
+ letter-spacing: 0.2px;
53
+ }
54
+ .content-editor-topbar-file .content-editor-dirty-indicator
55
+ {
56
+ color: #E8A94D;
57
+ font-weight: bold;
58
+ }
59
+ /* Left spacer pushes actions to the right */
60
+ .content-editor-topbar-spacer
61
+ {
62
+ flex: 1;
63
+ }
64
+ .content-editor-topbar-status
65
+ {
66
+ padding: 0 12px;
67
+ font-size: 0.78rem;
68
+ flex-shrink: 0;
69
+ }
70
+ .content-editor-status-saving
71
+ {
72
+ color: #E8A94D;
73
+ }
74
+ .content-editor-status-saved
75
+ {
76
+ color: #7BC47F;
77
+ }
78
+ .content-editor-status-error
79
+ {
80
+ color: #D9534F;
81
+ }
82
+ .content-editor-topbar-stats
83
+ {
84
+ font-size: 0.72rem;
85
+ color: #8A7F72;
86
+ white-space: nowrap;
87
+ padding: 0 8px;
88
+ flex-shrink: 0;
89
+ letter-spacing: 0.2px;
90
+ }
91
+ .content-editor-topbar-actions
92
+ {
93
+ display: flex;
94
+ align-items: center;
95
+ gap: 8px;
96
+ padding: 0 12px;
97
+ flex-shrink: 0;
98
+ }
99
+ .content-editor-topbar-btn
100
+ {
101
+ padding: 6px 14px;
102
+ border: none;
103
+ border-radius: 4px;
104
+ cursor: pointer;
105
+ font-size: 0.8rem;
106
+ font-weight: 600;
107
+ }
108
+ .content-editor-topbar-btn-save
109
+ {
110
+ background: #2E7D74;
111
+ color: #FFF;
112
+ }
113
+ .content-editor-topbar-btn-save:hover
114
+ {
115
+ background: #3A9E92;
116
+ }
117
+ .content-editor-topbar-btn-save:disabled
118
+ {
119
+ background: #5E5549;
120
+ color: #8A7F72;
121
+ cursor: not-allowed;
122
+ }
123
+ .content-editor-topbar-btn-close
124
+ {
125
+ background: transparent;
126
+ color: #B8AFA4;
127
+ border: 1px solid #5E5549;
128
+ }
129
+ .content-editor-topbar-btn-close:hover
130
+ {
131
+ color: #E8E0D4;
132
+ border-color: #8A7F72;
133
+ background: rgba(255, 255, 255, 0.05);
134
+ }
135
+ /* Close-file confirmation overlay */
136
+ .content-editor-confirm-overlay
137
+ {
138
+ display: none;
139
+ position: fixed;
140
+ top: 0;
141
+ left: 0;
142
+ right: 0;
143
+ bottom: 0;
144
+ z-index: 1099;
145
+ background: rgba(0, 0, 0, 0.35);
146
+ }
147
+ .content-editor-confirm-overlay.open
148
+ {
149
+ display: flex;
150
+ align-items: center;
151
+ justify-content: center;
152
+ }
153
+ .content-editor-confirm-panel
154
+ {
155
+ background: #FFF;
156
+ border: 1px solid #DDD6CA;
157
+ border-radius: 10px;
158
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2);
159
+ width: 360px;
160
+ max-width: 90vw;
161
+ overflow: hidden;
162
+ }
163
+ .content-editor-confirm-body
164
+ {
165
+ padding: 24px 22px 16px;
166
+ text-align: center;
167
+ }
168
+ .content-editor-confirm-icon
169
+ {
170
+ font-size: 2rem;
171
+ margin-bottom: 8px;
172
+ color: #E8A94D;
173
+ }
174
+ .content-editor-confirm-title
175
+ {
176
+ font-size: 0.95rem;
177
+ font-weight: 600;
178
+ color: #3D3229;
179
+ margin-bottom: 6px;
180
+ }
181
+ .content-editor-confirm-message
182
+ {
183
+ font-size: 0.82rem;
184
+ color: #5E5549;
185
+ margin-bottom: 16px;
186
+ line-height: 1.5;
187
+ }
188
+ .content-editor-confirm-actions
189
+ {
190
+ display: flex;
191
+ gap: 10px;
192
+ justify-content: center;
193
+ }
194
+ .content-editor-confirm-btn
195
+ {
196
+ padding: 8px 20px;
197
+ border: none;
198
+ border-radius: 5px;
199
+ font-size: 0.82rem;
200
+ font-weight: 600;
201
+ cursor: pointer;
202
+ }
203
+ .content-editor-confirm-btn-discard
204
+ {
205
+ background: #D9534F;
206
+ color: #FFF;
207
+ }
208
+ .content-editor-confirm-btn-discard:hover
209
+ {
210
+ background: #C9302C;
211
+ }
212
+ .content-editor-confirm-btn-cancel
213
+ {
214
+ background: transparent;
215
+ color: #5E5549;
216
+ border: 1px solid #DDD6CA;
217
+ }
218
+ .content-editor-confirm-btn-cancel:hover
219
+ {
220
+ background: #F0EDE8;
221
+ }
222
+ .content-editor-confirm-footer
223
+ {
224
+ padding: 10px 22px;
225
+ border-top: 1px solid #EDE9E3;
226
+ font-size: 0.72rem;
227
+ color: #8A7F72;
228
+ text-align: center;
229
+ }
230
+ .content-editor-confirm-kbd
231
+ {
232
+ display: inline-block;
233
+ padding: 1px 5px;
234
+ font-size: 0.68rem;
235
+ font-family: monospace;
236
+ background: #F0EDE8;
237
+ border: 1px solid #DDD6CA;
238
+ border-radius: 3px;
239
+ color: #5E5549;
240
+ }
241
+ `,
242
+
243
+ Templates:
244
+ [
245
+ {
246
+ Hash: "ContentEditor-TopBar-Template",
247
+ Template: /*html*/`
248
+ <div class="content-editor-topbar">
249
+ <div class="content-editor-topbar-brand">Content Editor</div>
250
+ <div class="content-editor-topbar-file">
251
+ <span class="content-editor-topbar-filename">{~D:AppData.ContentEditor.CurrentFile~}</span>{~D:AppData.ContentEditor.DirtyIndicatorHTML~}
252
+ </div>
253
+ <div class="content-editor-topbar-spacer"></div>
254
+ <div class="content-editor-topbar-status {~D:AppData.ContentEditor.SaveStatusClass~}">
255
+ {~D:AppData.ContentEditor.SaveStatus~}
256
+ </div>
257
+ <span class="content-editor-topbar-stats" id="ContentEditor-Stats"></span>
258
+ <div class="content-editor-topbar-actions">
259
+ <button class="content-editor-topbar-btn content-editor-topbar-btn-save"
260
+ onclick="{~P~}.PictApplication.saveCurrentFile()"
261
+ {~D:AppData.ContentEditor.SaveDisabledAttr~} {~D:AppData.ContentEditor.SaveVisibilityAttr~}>Save</button>
262
+ <button class="content-editor-topbar-btn content-editor-topbar-btn-close"
263
+ onclick="{~P~}.PictApplication.closeCurrentFile()"
264
+ {~D:AppData.ContentEditor.CloseVisibilityAttr~}>Close</button>
265
+ <div id="ContentEditor-SettingsPanel-Container"></div>
266
+ </div>
267
+ </div>
268
+ <div class="content-editor-confirm-overlay" id="ContentEditor-ConfirmOverlay"
269
+ onclick="{~P~}.PictApplication.cancelCloseFile()">
270
+ <div class="content-editor-confirm-panel" onclick="event.stopPropagation()">
271
+ <div class="content-editor-confirm-body">
272
+ <div class="content-editor-confirm-icon">&#x26A0;</div>
273
+ <div class="content-editor-confirm-title">Unsaved Changes</div>
274
+ <div class="content-editor-confirm-message">
275
+ This file has unsaved changes.<br>Close without saving?
276
+ </div>
277
+ <div class="content-editor-confirm-actions">
278
+ <button class="content-editor-confirm-btn content-editor-confirm-btn-discard"
279
+ onclick="{~P~}.PictApplication.confirmCloseFile()">Discard &amp; Close</button>
280
+ <button class="content-editor-confirm-btn content-editor-confirm-btn-cancel"
281
+ onclick="{~P~}.PictApplication.cancelCloseFile()">Cancel</button>
282
+ </div>
283
+ </div>
284
+ <div class="content-editor-confirm-footer">
285
+ <span class="content-editor-confirm-kbd">Y</span> to discard &middot;
286
+ <span class="content-editor-confirm-kbd">N</span> or
287
+ <span class="content-editor-confirm-kbd">Esc</span> to cancel
288
+ </div>
289
+ </div>
290
+ </div>
291
+ `
292
+ }
293
+ ],
294
+
295
+ Renderables:
296
+ [
297
+ {
298
+ RenderableHash: "ContentEditor-TopBar-Display",
299
+ TemplateHash: "ContentEditor-TopBar-Template",
300
+ DestinationAddress: "#ContentEditor-TopBar-Container",
301
+ RenderMethod: "replace"
302
+ }
303
+ ]
304
+ };
305
+
306
+ class ContentEditorTopBarView extends libPictView
307
+ {
308
+ constructor(pFable, pOptions, pServiceHash)
309
+ {
310
+ super(pFable, pOptions, pServiceHash);
311
+ }
312
+
313
+ onBeforeRender(pRenderable, pRenderDestinationAddress, pRecord)
314
+ {
315
+ let tmpEditor = this.pict.AppData.ContentEditor;
316
+
317
+ // Dirty indicator
318
+ tmpEditor.DirtyIndicatorHTML = tmpEditor.IsDirty
319
+ ? ' <span class="content-editor-dirty-indicator">*</span>'
320
+ : '';
321
+
322
+ // Disable save button if no file or currently saving
323
+ tmpEditor.SaveDisabledAttr = (!tmpEditor.CurrentFile || tmpEditor.IsSaving)
324
+ ? 'disabled'
325
+ : '';
326
+
327
+ // Hide save button entirely until the user makes an edit
328
+ tmpEditor.SaveVisibilityAttr = (tmpEditor.IsDirty || tmpEditor.IsSaving || tmpEditor.SaveStatus)
329
+ ? ''
330
+ : 'style="display:none"';
331
+
332
+ // Hide close button when no file is open
333
+ tmpEditor.CloseVisibilityAttr = tmpEditor.CurrentFile
334
+ ? ''
335
+ : 'style="display:none"';
336
+
337
+ // Build viewer hash link
338
+ if (tmpEditor.CurrentFile)
339
+ {
340
+ let tmpViewerPath = tmpEditor.CurrentFile.replace(/\.md$/, '');
341
+ tmpEditor.ViewerHash = '#/page/' + tmpViewerPath;
342
+ }
343
+ else
344
+ {
345
+ tmpEditor.ViewerHash = '';
346
+ }
347
+
348
+ return super.onBeforeRender(pRenderable, pRenderDestinationAddress, pRecord);
349
+ }
350
+
351
+ onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent)
352
+ {
353
+ // Render the settings panel inside our container
354
+ let tmpSettingsPanel = this.pict.views['ContentEditor-SettingsPanel'];
355
+ if (tmpSettingsPanel)
356
+ {
357
+ tmpSettingsPanel.render();
358
+ }
359
+
360
+ return super.onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent);
361
+ }
362
+ }
363
+
364
+ module.exports = ContentEditorTopBarView;
365
+
366
+ module.exports.default_configuration = _ViewConfiguration;