synthos 0.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.
Files changed (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +71 -0
  3. package/bin/synthos.js +3 -0
  4. package/default-pages/[application].html +87 -0
  5. package/default-pages/[markdown].html +261 -0
  6. package/default-pages/[sidebar].html +89 -0
  7. package/default-pages/[split-application].html +133 -0
  8. package/default-pages/json_tools.html +176 -0
  9. package/default-scripts/android.terminal.json +7 -0
  10. package/default-scripts/linux-terminal.json +7 -0
  11. package/default-scripts/mac-terminal.json +7 -0
  12. package/default-scripts/windows-terminal.json +7 -0
  13. package/dist/files.d.ts +9 -0
  14. package/dist/files.d.ts.map +1 -0
  15. package/dist/files.js +79 -0
  16. package/dist/files.js.map +1 -0
  17. package/dist/index.d.ts +7 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +23 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/init.d.ts +9 -0
  22. package/dist/init.d.ts.map +1 -0
  23. package/dist/init.js +59 -0
  24. package/dist/init.js.map +1 -0
  25. package/dist/pages.d.ts +6 -0
  26. package/dist/pages.d.ts.map +1 -0
  27. package/dist/pages.js +55 -0
  28. package/dist/pages.js.map +1 -0
  29. package/dist/scripts.d.ts +14 -0
  30. package/dist/scripts.d.ts.map +1 -0
  31. package/dist/scripts.js +103 -0
  32. package/dist/scripts.js.map +1 -0
  33. package/dist/service/createCompletePrompt.d.ts +4 -0
  34. package/dist/service/createCompletePrompt.d.ts.map +1 -0
  35. package/dist/service/createCompletePrompt.js +42 -0
  36. package/dist/service/createCompletePrompt.js.map +1 -0
  37. package/dist/service/generateImage.d.ts +32 -0
  38. package/dist/service/generateImage.d.ts.map +1 -0
  39. package/dist/service/generateImage.js +71 -0
  40. package/dist/service/generateImage.js.map +1 -0
  41. package/dist/service/index.d.ts +8 -0
  42. package/dist/service/index.d.ts.map +1 -0
  43. package/dist/service/index.js +24 -0
  44. package/dist/service/index.js.map +1 -0
  45. package/dist/service/requiresSettings.d.ts +3 -0
  46. package/dist/service/requiresSettings.d.ts.map +1 -0
  47. package/dist/service/requiresSettings.js +24 -0
  48. package/dist/service/requiresSettings.js.map +1 -0
  49. package/dist/service/server.d.ts +4 -0
  50. package/dist/service/server.d.ts.map +1 -0
  51. package/dist/service/server.js +26 -0
  52. package/dist/service/server.js.map +1 -0
  53. package/dist/service/transformPage.d.ts +11 -0
  54. package/dist/service/transformPage.d.ts.map +1 -0
  55. package/dist/service/transformPage.js +119 -0
  56. package/dist/service/transformPage.js.map +1 -0
  57. package/dist/service/useApiRoutes.d.ts +4 -0
  58. package/dist/service/useApiRoutes.d.ts.map +1 -0
  59. package/dist/service/useApiRoutes.js +95 -0
  60. package/dist/service/useApiRoutes.js.map +1 -0
  61. package/dist/service/useDataRoutes.d.ts +4 -0
  62. package/dist/service/useDataRoutes.d.ts.map +1 -0
  63. package/dist/service/useDataRoutes.js +98 -0
  64. package/dist/service/useDataRoutes.js.map +1 -0
  65. package/dist/service/usePageRoutes.d.ts +5 -0
  66. package/dist/service/usePageRoutes.d.ts.map +1 -0
  67. package/dist/service/usePageRoutes.js +132 -0
  68. package/dist/service/usePageRoutes.js.map +1 -0
  69. package/dist/settings.d.ts +13 -0
  70. package/dist/settings.d.ts.map +1 -0
  71. package/dist/settings.js +55 -0
  72. package/dist/settings.js.map +1 -0
  73. package/dist/synthos-cli.d.ts +2 -0
  74. package/dist/synthos-cli.d.ts.map +1 -0
  75. package/dist/synthos-cli.js +43 -0
  76. package/dist/synthos-cli.js.map +1 -0
  77. package/images/home.png +0 -0
  78. package/images/page-management.png +0 -0
  79. package/images/settings.png +0 -0
  80. package/images/synthos-square.png +0 -0
  81. package/package.json +58 -0
  82. package/required-pages/apis.html +347 -0
  83. package/required-pages/home.html +83 -0
  84. package/required-pages/pages.html +135 -0
  85. package/required-pages/scripts.html +335 -0
  86. package/required-pages/settings.html +158 -0
  87. package/src/files.ts +49 -0
  88. package/src/index.ts +6 -0
  89. package/src/init.ts +66 -0
  90. package/src/pages.ts +55 -0
  91. package/src/scripts.ts +130 -0
  92. package/src/service/createCompletePrompt.ts +40 -0
  93. package/src/service/generateImage.ts +101 -0
  94. package/src/service/index.ts +7 -0
  95. package/src/service/requiresSettings.ts +22 -0
  96. package/src/service/server.ts +26 -0
  97. package/src/service/transformPage.ts +135 -0
  98. package/src/service/useApiRoutes.ts +95 -0
  99. package/src/service/useDataRoutes.ts +97 -0
  100. package/src/service/usePageRoutes.ts +147 -0
  101. package/src/settings.ts +60 -0
  102. package/src/synthos-cli.ts +38 -0
@@ -0,0 +1,347 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SynthOS - APIs</title>
7
+ <style>
8
+ * { margin: 0; padding: 0; box-sizing: border-box; }
9
+ body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #1a1a1a; color: #e0e0e0; height: 100vh; display: flex; }
10
+ .chat-panel { width: 30%; background: #2a2a2a; box-shadow: 0 0 10px rgba(0,0,0,0.3); padding: 20px; display: flex; flex-direction: column; }
11
+ .chat-header { font-size: 24px; padding: 10px; background: #3a7bc8; color: white; text-align: center; border-radius: 10px 10px 0 0; }
12
+ .chat-messages { flex-grow: 1; overflow-y: auto; padding: 15px; margin-top: 10px; background: #333; border-radius: 10px; }
13
+ .chat-message { margin-bottom: 15px; padding: 10px; background: #444; border-radius: 15px; box-shadow: 0 2px 5px rgba(0,0,0,0.2); }
14
+ .chat-message p { margin-bottom: 5px; line-height: 1.4; }
15
+ .chat-message p strong { font-weight: 600; color: #4a90e2; }
16
+ .chat-message p code { background: #555; padding: 2px 4px; border-radius: 3px; font-family: 'Courier New', Courier, monospace; color: #e0e0e0; }
17
+ .link-group { display: flex; justify-content: space-between; margin: 15px 0; }
18
+ .link-group a { font-size: 14px; color: #4a90e2; text-decoration: none; padding: 5px 10px; border-radius: 5px; transition: background-color 0.3s; }
19
+ .link-group a:hover { background-color: #3a3a3a; }
20
+ form { display: flex; flex-direction: column; width: 100%; }
21
+ .chat-input, .chat-submit { padding: 12px; border: none; border-radius: 25px; width: 100%; font-size: 14px; }
22
+ .chat-input { background: #444; color: #e0e0e0; margin-bottom: 10px; box-shadow: inset 0 1px 3px rgba(0,0,0,0.3); }
23
+ .chat-submit { background: #3a7bc8; color: white; cursor: pointer; transition: background-color 0.3s; }
24
+ .chat-submit:hover { background: #2a6cb8; }
25
+ .viewer-panel { width: 70%; padding: 20px; background: #2a2a2a; display: flex; flex-direction: column; justify-content: flex-start; align-items: center; box-shadow: -5px 0 10px rgba(0,0,0,0.2); overflow-y: auto; }
26
+ .loading-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(26, 26, 26, 0.8); display: none; justify-content: center; align-items: center; z-index: 1000; }
27
+ .spinner { border: 8px solid #333; border-top: 8px solid #3a7bc8; border-radius: 50%; width: 60px; height: 60px; animation: spin 1s linear infinite; }
28
+ @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
29
+ ::-webkit-scrollbar { width: 10px; }
30
+ ::-webkit-scrollbar-track { background: #333; }
31
+ ::-webkit-scrollbar-thumb { background: #555; border-radius: 5px; }
32
+ ::-webkit-scrollbar-thumb:hover { background: #666; }
33
+ .dialog-title { font-size: 24px; color: #f0f0f0; background: #3a7bc8; padding: 10px; border-radius: 10px 10px 0 0; width: 100%; text-align: center; }
34
+ .dialog-content { font-size: 18px; color: #ccc; padding: 10px; margin-top:10px; flex-grow: 1; width: 100%; }
35
+ .api-section { margin: 10px 0; padding: 10px; background: #333; border-radius: 10px; width: 100%; }
36
+ .api-header { font-size: 20px; cursor: pointer; background: #444; padding: 10px; border-radius: 10px; text-align: left; transition: background-color 0.3s; }
37
+ .api-header:hover { background: #555; }
38
+ .api-content { display: none; margin-top: 10px; text-align: left; padding: 10px; background: #3a3a3a; border-radius: 10px; }
39
+ .api-input { margin-top: 10px; }
40
+ .api-input input, .api-input textarea, .api-input select { width: 100%; padding: 10px; margin-bottom: 10px; border-radius: 5px; border: none; background: #444; color: #fff; }
41
+ .api-input textarea { min-height: 100px; resize: vertical; }
42
+ .api-input button { padding: 10px 15px; border: none; border-radius: 25px; background: #3a7bc8; color: #fff; cursor: pointer; transition: background-color 0.3s; }
43
+ .api-input button:hover { background: #2a6cb8; }
44
+ .api-input button:disabled { background: #666; cursor: not-allowed; }
45
+ .api-output { margin-top: 10px; min-height: 200px; background: #222; color: #fff; padding: 10px; border-radius: 5px; overflow-y: auto; white-space: pre-wrap; }
46
+ .generated-image { max-width: 100%; height: auto; margin-top: 10px; border-radius: 5px; }
47
+ </style>
48
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js"></script>
49
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/14.1.1/marked.min.js"></script>
50
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/11.1.0/mermaid.min.js"></script>
51
+ </head>
52
+ <body>
53
+ <div class="chat-panel">
54
+ <div class="chat-header">SynthOS</div>
55
+ <div class="chat-messages" id="chatMessages">
56
+ <div class="chat-message"><p><strong>SynthOS:</strong> Expand the individual API operations to test calls.</p></div>
57
+ </div>
58
+ <div class="link-group">
59
+ <a href="#" id="saveLink">Save</a>
60
+ <a href="/pages" id="pagesLink">Pages</a>
61
+ <a href="#" id="resetLink">Reset</a>
62
+ </div>
63
+ <form action="/" method="POST" id="chatForm">
64
+ <input type="text" class="chat-input" id="chatInput" name="message" placeholder="Type a message...">
65
+ <button type="submit" class="chat-submit">Send</button>
66
+ </form>
67
+ </div>
68
+ <div class="viewer-panel" id="viewerPanel">
69
+ <div class="dialog-title">API Explorer</div>
70
+ <div class="dialog-content">
71
+ <div class="api-section">
72
+ <div class="api-header" onclick="toggleSection(this)">GET /api/data/:table</div>
73
+ <div class="api-content">
74
+ This operation retrieves all rows from the specified table. The response is an array of JSON objects, each representing a row in the table.
75
+ <div class="api-input">
76
+ <input type="text" placeholder="Table Name" />
77
+ <button onclick="callApi(event, 'GET', '/api/data/')">Submit</button>
78
+ </div>
79
+ <div class="api-output"></div>
80
+ </div>
81
+ </div>
82
+ <div class="api-section">
83
+ <div class="api-header" onclick="toggleSection(this)">GET /api/data/:table/:id</div>
84
+ <div class="api-content">
85
+ This operation retrieves a single row from the specified table using the provided ID. The response is a JSON object representing the row.
86
+ <div class="api-input">
87
+ <input type="text" placeholder="Table Name" />
88
+ <input type="text" placeholder="ID" />
89
+ <button onclick="callApi(event, 'GET', '/api/data/')">Submit</button>
90
+ </div>
91
+ <div class="api-output"></div>
92
+ </div>
93
+ </div>
94
+ <div class="api-section">
95
+ <div class="api-header" onclick="toggleSection(this)">POST /api/data/:table/:id</div>
96
+ <div class="api-content">
97
+ This operation saves a single row to the specified table. The request should include a JSON object representing the row. The response indicates success.
98
+ <div class="api-input">
99
+ <input type="text" placeholder="Table Name" />
100
+ <input type="text" placeholder="ID" />
101
+ <textarea placeholder="JSON Data"></textarea>
102
+ <button onclick="callApi(event, 'POST', '/api/data/')">Submit</button>
103
+ </div>
104
+ <div class="api-output"></div>
105
+ </div>
106
+ </div>
107
+ <div class="api-section">
108
+ <div class="api-header" onclick="toggleSection(this)">DELETE /api/data/:table/:id</div>
109
+ <div class="api-content">
110
+ This operation deletes a single row from the specified table using the provided ID. The response indicates success.
111
+ <div class="api-input">
112
+ <input type="text" placeholder="Table Name" />
113
+ <input type="text" placeholder="ID" />
114
+ <button onclick="callApi(event, 'DELETE', '/api/data/')">Submit</button>
115
+ </div>
116
+ <div class="api-output"></div>
117
+ </div>
118
+ </div>
119
+ <div class="api-section">
120
+ <div class="api-header" onclick="toggleSection(this)">GET /api/pages</div>
121
+ <div class="api-content">
122
+ This operation retrieves a list of all available pages. The response is an array of page names.
123
+ <div class="api-input">
124
+ <button onclick="callApi(event, 'GET', '/api/pages')">Submit</button>
125
+ </div>
126
+ <div class="api-output"></div>
127
+ </div>
128
+ </div>
129
+ <div class="api-section">
130
+ <div class="api-header" onclick="toggleSection(this)">POST /api/generate/image</div>
131
+ <div class="api-content">
132
+ This operation generates an image based on a prompt. You can specify the shape and style of the image.
133
+ <div class="api-input">
134
+ <input type="text" placeholder="Prompt" id="imagePrompt" />
135
+ <select id="imageShape">
136
+ <option value="square">Square</option>
137
+ <option value="portrait">Portrait</option>
138
+ <option value="landscape">Landscape</option>
139
+ </select>
140
+ <select id="imageStyle">
141
+ <option value="vivid">Vivid</option>
142
+ <option value="natural">Natural</option>
143
+ </select>
144
+ <button onclick="generateImage(event)">Generate Image</button>
145
+ </div>
146
+ <div class="api-output"></div>
147
+ </div>
148
+ </div>
149
+ <div class="api-section">
150
+ <div class="api-header" onclick="toggleSection(this)">POST /api/generate/completion</div>
151
+ <div class="api-content">
152
+ This operation generates a text completion based on a prompt. You can optionally specify the temperature for controlling randomness.
153
+ <div class="api-input">
154
+ <textarea placeholder="Prompt" id="completionPrompt"></textarea>
155
+ <input type="number" placeholder="Temperature (optional)" id="completionTemperature" step="0.1" min="0" max="1" />
156
+ <button onclick="generateCompletion(event)">Generate Completion</button>
157
+ </div>
158
+ <div class="api-output"></div>
159
+ </div>
160
+ </div>
161
+ <div class="api-section">
162
+ <div class="api-header" onclick="toggleSection(this)">POST /api/scripts/:id</div>
163
+ <div class="api-content">
164
+ This operation executes a script with the specified ID and passes in the provided variables. The response contains the output of the script execution.
165
+ <div class="api-input">
166
+ <input type="text" placeholder="Script ID" id="scriptId" />
167
+ <textarea placeholder="Variables (JSON format)" id="scriptVariables"></textarea>
168
+ <button onclick="executeScript(event)">Execute Script</button>
169
+ </div>
170
+ <div class="api-output"></div>
171
+ </div>
172
+ </div>
173
+ </div>
174
+ </div>
175
+ <div id="thoughts" style="display: none;">I've shown the user a list of available API's.</div>
176
+ <div id="loadingOverlay" class="loading-overlay"><div class="spinner"></div></div>
177
+ <script>
178
+ // Basic chat functionality
179
+ document.getElementById("chatInput").focus();
180
+ document.getElementById("chatForm").addEventListener('submit', () => {
181
+ document.getElementById("loadingOverlay").style.display = 'flex';
182
+ document.getElementById("chatForm").action = window.location.pathname;
183
+ });
184
+ document.getElementById("saveLink").addEventListener("click", function() {
185
+ const pageName = prompt("Enter the name of the page to save as:");
186
+ if (pageName) {
187
+ window.location.href = `${window.location.pathname}/save?name=${encodeURIComponent(pageName)}`;
188
+ }
189
+ });
190
+ document.getElementById("resetLink").addEventListener("click", function() {
191
+ window.location.href = `${window.location.pathname}/reset`;
192
+ });
193
+ window.onload = function() {
194
+ const chatMessages = document.getElementById('chatMessages');
195
+ chatMessages.scrollTo({
196
+ top: chatMessages.scrollHeight,
197
+ behavior: 'smooth'
198
+ });
199
+ };
200
+
201
+ // Toggle functionality for API sections
202
+ function toggleSection(header) {
203
+ const content = header.nextElementSibling;
204
+ content.style.display = content.style.display === 'block' ? 'none' : 'block';
205
+ }
206
+
207
+ // Function to call the server API
208
+ function callApi(event, method, endpoint) {
209
+ event.preventDefault();
210
+ const button = event.target;
211
+ button.disabled = true;
212
+ const inputs = event.target.parentElement.querySelectorAll('input, textarea');
213
+ let url = endpoint;
214
+ let data = {};
215
+
216
+ inputs.forEach(input => {
217
+ if (input.placeholder === 'Table Name') {
218
+ url += input.value;
219
+ } else if (input.placeholder === 'ID') {
220
+ url += '/' + input.value;
221
+ } else if (input.placeholder === 'JSON Data') {
222
+ data = JSON.parse(input.value);
223
+ }
224
+ });
225
+
226
+ fetch(url, {
227
+ method: method,
228
+ headers: {
229
+ 'Content-Type': 'application/json'
230
+ },
231
+ body: method === 'POST' ? JSON.stringify(data) : null
232
+ })
233
+ .then(response => response.json())
234
+ .then(data => {
235
+ console.log('Success:', data);
236
+ const outputBox = event.target.parentElement.nextElementSibling;
237
+ outputBox.textContent = JSON.stringify(data, null, 2);
238
+ })
239
+ .catch((error) => {
240
+ console.error('Error:', error);
241
+ alert('API call failed! Check console for details.');
242
+ })
243
+ .finally(() => {
244
+ button.disabled = false;
245
+ });
246
+ }
247
+
248
+ // Function to generate image
249
+ function generateImage(event) {
250
+ event.preventDefault();
251
+ const button = event.target;
252
+ button.disabled = true;
253
+ const prompt = document.getElementById('imagePrompt').value;
254
+ const shape = document.getElementById('imageShape').value;
255
+ const style = document.getElementById('imageStyle').value;
256
+ const outputBox = event.target.parentElement.nextElementSibling;
257
+
258
+ fetch('/api/generate/image', {
259
+ method: 'POST',
260
+ headers: {
261
+ 'Content-Type': 'application/json'
262
+ },
263
+ body: JSON.stringify({ prompt, shape, style })
264
+ })
265
+ .then(response => response.json())
266
+ .then(data => {
267
+ console.log('Success:', data);
268
+ outputBox.textContent = JSON.stringify(data, null, 2);
269
+ if (data.url) {
270
+ const img = document.createElement('img');
271
+ img.src = data.url;
272
+ img.alt = 'Generated Image';
273
+ img.className = 'generated-image';
274
+ outputBox.appendChild(img);
275
+ }
276
+ })
277
+ .catch((error) => {
278
+ console.error('Error:', error);
279
+ alert('Image generation failed! Check console for details.');
280
+ })
281
+ .finally(() => {
282
+ button.disabled = false;
283
+ });
284
+ }
285
+
286
+ // Function to generate completion
287
+ function generateCompletion(event) {
288
+ event.preventDefault();
289
+ const button = event.target;
290
+ button.disabled = true;
291
+ const prompt = document.getElementById('completionPrompt').value;
292
+ const temperature = document.getElementById('completionTemperature').value;
293
+ const outputBox = event.target.parentElement.nextElementSibling;
294
+
295
+ fetch('/api/generate/completion', {
296
+ method: 'POST',
297
+ headers: {
298
+ 'Content-Type': 'application/json'
299
+ },
300
+ body: JSON.stringify({ prompt, temperature: parseFloat(temperature) || undefined })
301
+ })
302
+ .then(response => response.json())
303
+ .then(data => {
304
+ console.log('Success:', data);
305
+ outputBox.textContent = JSON.stringify(data, null, 2);
306
+ })
307
+ .catch((error) => {
308
+ console.error('Error:', error);
309
+ alert('Completion generation failed! Check console for details.');
310
+ })
311
+ .finally(() => {
312
+ button.disabled = false;
313
+ });
314
+ }
315
+
316
+ // Function to execute script
317
+ function executeScript(event) {
318
+ event.preventDefault();
319
+ const button = event.target;
320
+ button.disabled = true;
321
+ const scriptId = document.getElementById('scriptId').value;
322
+ const variables = JSON.parse(document.getElementById('scriptVariables').value);
323
+ const outputBox = event.target.parentElement.nextElementSibling;
324
+
325
+ fetch(`/api/scripts/${scriptId}`, {
326
+ method: 'POST',
327
+ headers: {
328
+ 'Content-Type': 'application/json'
329
+ },
330
+ body: JSON.stringify(variables)
331
+ })
332
+ .then(response => response.json())
333
+ .then(data => {
334
+ console.log('Success:', data);
335
+ outputBox.textContent = JSON.stringify(data, null, 2);
336
+ })
337
+ .catch((error) => {
338
+ console.error('Error:', error);
339
+ alert('Script execution failed! Check console for details.');
340
+ })
341
+ .finally(() => {
342
+ button.disabled = false;
343
+ });
344
+ }
345
+ </script>
346
+ </body>
347
+ </html>
@@ -0,0 +1,83 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SynthOS</title>
7
+ <style>
8
+ * { margin: 0; padding: 0; box-sizing: border-box; }
9
+ body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #1a1a1a; color: #e0e0e0; height: 100vh; display: flex; }
10
+ .chat-panel { width: 30%; background: #2a2a2a; box-shadow: 0 0 10px rgba(0,0,0,0.3); padding: 20px; display: flex; flex-direction: column; }
11
+ .chat-header { font-size: 24px; padding: 10px; background: #3a7bc8; color: white; text-align: center; border-radius: 10px 10px 0 0; }
12
+ .chat-messages { flex-grow: 1; overflow-y: auto; padding: 15px; margin-top: 10px; background: #333; border-radius: 10px; }
13
+ .chat-message { margin-bottom: 15px; padding: 10px; background: #444; border-radius: 15px; box-shadow: 0 2px 5px rgba(0,0,0,0.2); }
14
+ .chat-message p { margin-bottom: 5px; line-height: 1.4; }
15
+ .chat-message p strong { font-weight: 600; color: #4a90e2; }
16
+ .chat-message p code { background: #555; padding: 2px 4px; border-radius: 3px; font-family: 'Courier New', Courier, monospace; color: #e0e0e0; }
17
+ .link-group { display: flex; justify-content: space-between; margin: 15px 0; }
18
+ .link-group a { font-size: 14px; color: #4a90e2; text-decoration: none; padding: 5px 10px; border-radius: 5px; transition: background-color 0.3s; }
19
+ .link-group a:hover { background-color: #3a3a3a; }
20
+ form { display: flex; flex-direction: column; width: 100%; }
21
+ .chat-input, .chat-submit { padding: 12px; border: none; border-radius: 25px; width: 100%; font-size: 14px; }
22
+ .chat-input { background: #444; color: #e0e0e0; margin-bottom: 10px; box-shadow: inset 0 1px 3px rgba(0,0,0,0.3); }
23
+ .chat-submit { background: #3a7bc8; color: white; cursor: pointer; transition: background-color 0.3s; }
24
+ .chat-submit:hover { background: #2a6cb8; }
25
+ .viewer-panel { width: 70%; padding: 30px; background: #2a2a2a; display: flex; flex-direction: column; justify-content: center; align-items: center; box-shadow: -5px 0 10px rgba(0,0,0,0.2); }
26
+ .loading-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(26, 26, 26, 0.8); display: none; justify-content: center; align-items: center; z-index: 1000; }
27
+ .spinner { border: 8px solid #333; border-top: 8px solid #3a7bc8; border-radius: 50%; width: 60px; height: 60px; animation: spin 1s linear infinite; }
28
+ @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
29
+ ::-webkit-scrollbar { width: 10px; }
30
+ ::-webkit-scrollbar-track { background: #333; }
31
+ ::-webkit-scrollbar-thumb { background: #555; border-radius: 5px; }
32
+ ::-webkit-scrollbar-thumb:hover { background: #666; }
33
+ </style>
34
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js"></script>
35
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/14.1.1/marked.min.js"></script>
36
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/11.1.0/mermaid.min.js"></script>
37
+ </head>
38
+ <body>
39
+ <div class="chat-panel">
40
+ <div class="chat-header">SynthOS</div>
41
+ <div class="chat-messages" id="chatMessages">
42
+ <div class="chat-message"><p><strong>SynthOS:</strong> What can I create for you?</p></div>
43
+ </div>
44
+ <div class="link-group">
45
+ <a href="#" id="saveLink">Save</a>
46
+ <a href="/pages" id="pagesLink">Pages</a>
47
+ <a href="#" id="resetLink">Reset</a>
48
+ </div>
49
+ <form action="/" method="POST" id="chatForm">
50
+ <input type="text" class="chat-input" id="chatInput" name="message" placeholder="Type a message...">
51
+ <button type="submit" class="chat-submit">Send</button>
52
+ </form>
53
+ </div>
54
+ <div class="viewer-panel" id="viewerPanel">
55
+ <!-- Viewer content will be rendered here -->
56
+ </div>
57
+ <div id="thoughts" style="display: none;">Prompt the user and ask them what they'd like to create.</div>
58
+ <div id="loadingOverlay" class="loading-overlay"><div class="spinner"></div></div>
59
+ <script>
60
+ document.getElementById("chatInput").focus();
61
+ document.getElementById("chatForm").addEventListener('submit', () => {
62
+ document.getElementById("loadingOverlay").style.display = 'flex';
63
+ document.getElementById("chatForm").action = window.location.pathname;
64
+ });
65
+ document.getElementById("saveLink").addEventListener("click", function() {
66
+ const pageName = prompt("Enter the name of the page to save as:");
67
+ if (pageName) {
68
+ window.location.href = `${window.location.pathname}/save?name=${encodeURIComponent(pageName)}`;
69
+ }
70
+ });
71
+ document.getElementById("resetLink").addEventListener("click", function() {
72
+ window.location.href = `${window.location.pathname}/reset`;
73
+ });
74
+ window.onload = function() {
75
+ const chatMessages = document.getElementById('chatMessages');
76
+ chatMessages.scrollTo({
77
+ top: chatMessages.scrollHeight,
78
+ behavior: 'smooth'
79
+ });
80
+ };
81
+ </script>
82
+ </body>
83
+ </html>
@@ -0,0 +1,135 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SynthOS - Pages</title>
7
+ <style>
8
+ * { margin: 0; padding: 0; box-sizing: border-box; }
9
+ body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #1a1a1a; color: #e0e0e0; height: 100vh; display: flex; }
10
+ .chat-panel { width: 30%; background: #2a2a2a; box-shadow: 0 0 10px rgba(0,0,0,0.3); padding: 20px; display: flex; flex-direction: column; }
11
+ .chat-header { font-size: 24px; padding: 10px; background: #3a7bc8; color: white; text-align: center; border-radius: 10px 10px 0 0; }
12
+ .chat-messages { flex-grow: 1; overflow-y: auto; padding: 15px; margin-top: 10px; background: #333; border-radius: 10px; }
13
+ .chat-message { margin-bottom: 15px; padding: 10px; background: #444; border-radius: 15px; box-shadow: 0 2px 5px rgba(0,0,0,0.2); }
14
+ .chat-message p { margin-bottom: 5px; line-height: 1.4; }
15
+ .chat-message p strong { font-weight: 600; color: #4a90e2; }
16
+ .chat-message p code { background: #555; padding: 2px 4px; border-radius: 3px; font-family: 'Courier New', Courier, monospace; color: #e0e0e0; }
17
+ .link-group { display: flex; justify-content: space-between; margin: 15px 0; }
18
+ .link-group a { font-size: 14px; color: #4a90e2; text-decoration: none; padding: 5px 10px; border-radius: 5px; transition: background-color 0.3s; }
19
+ .link-group a:hover { background-color: #3a3a3a; }
20
+ form { display: flex; flex-direction: column; width: 100%; }
21
+ .chat-input, .chat-submit { padding: 12px; border: none; border-radius: 25px; width: 100%; font-size: 14px; }
22
+ .chat-input { background: #444; color: #e0e0e0; margin-bottom: 10px; box-shadow: inset 0 1px 3px rgba(0,0,0,0.3); }
23
+ .chat-submit { background: #3a7bc8; color: white; cursor: pointer; transition: background-color 0.3s; }
24
+ .chat-submit:hover { background: #2a6cb8; }
25
+ .viewer-panel { width: 70%; padding: 20px; background: #2a2a2a; display: flex; flex-direction: column; justify-content: flex-start; align-items: center; box-shadow: -5px 0 10px rgba(0,0,0,0.2); overflow-y: auto; }
26
+ .loading-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(26, 26, 26, 0.8); display: none; justify-content: center; align-items: center; z-index: 1000; }
27
+ .spinner { border: 8px solid #333; border-top: 8px solid #3a7bc8; border-radius: 50%; width: 60px; height: 60px; animation: spin 1s linear infinite; }
28
+ @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
29
+ ::-webkit-scrollbar { width: 10px; }
30
+ ::-webkit-scrollbar-track { background: #333; }
31
+ ::-webkit-scrollbar-thumb { background: #555; border-radius: 5px; }
32
+ ::-webkit-scrollbar-thumb:hover { background: #666; }
33
+ .saved-pages { font-size: 24px; padding: 10px; background: #3a7bc8; color: white; text-align: center; border-radius: 10px 10px 0 0; width: 100%; margin-bottom: 20px; }
34
+ .page-category { margin-bottom: 50px; width: 100%; }
35
+ .category-title { font-size: 20px; color: #e0e0e0; margin-bottom: 15px; padding: 10px; border-radius: 5px; background: linear-gradient(45deg, #4a4a4a, #3a3a3a); box-shadow: 0 2px 4px rgba(0,0,0,0.2); }
36
+ .page-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 15px; }
37
+ .page-link { color: #fff; text-decoration: none; padding: 12px 15px; border-radius: 8px; display: flex; align-items: center; justify-content: center; background-color: #3a3a3a; transition: all 0.3s ease; height: 60px; box-shadow: 0 2px 4px rgba(0,0,0,0.2); }
38
+ .page-link:hover { background: #4a4a4a; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.3); }
39
+ </style>
40
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js"></script>
41
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/14.1.1/marked.min.js"></script>
42
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/11.1.0/mermaid.min.js"></script>
43
+ </head>
44
+ <body>
45
+ <div class="chat-panel">
46
+ <div class="chat-header">SynthOS</div>
47
+ <div class="chat-messages" id="chatMessages">
48
+ <div class="chat-message"><p><strong>SynthOS:</strong> Here are all of the created pages.</p></div>
49
+ </div>
50
+ <div class="link-group">
51
+ <a href="#" id="saveLink">Save</a>
52
+ <a href="/pages" id="pagesLink">Pages</a>
53
+ <a href="#" id="resetLink">Reset</a>
54
+ </div>
55
+ <form action="/" method="POST" id="chatForm">
56
+ <input type="text" class="chat-input" id="chatInput" name="message" placeholder="Type a message...">
57
+ <button type="submit" class="chat-submit">Send</button>
58
+ </form>
59
+ </div>
60
+ <div class="viewer-panel" id="viewerPanel">
61
+ <div class="saved-pages">Pages</div>
62
+ <div class="page-category">
63
+ <h2 class="category-title">System Pages</h2>
64
+ <div class="page-grid">
65
+ <a href="/home" class="page-link">Home</a>
66
+ <a href="/pages" class="page-link">Pages</a>
67
+ <a href="/settings" class="page-link">Settings</a>
68
+ <a href="/apis" class="page-link">API Explorer</a>
69
+ <a href="/scripts" class="page-link">Script Editor</a>
70
+ </div>
71
+ </div>
72
+ <div class="page-category">
73
+ <h2 class="category-title">Custom Pages</h2>
74
+ <div id="customPagesList" class="page-grid">
75
+ <!-- Custom pages will be dynamically loaded here -->
76
+ </div>
77
+ </div>
78
+ <div class="page-category">
79
+ <h2 class="category-title">Page Templates</h2>
80
+ <div id="templatesList" class="page-grid">
81
+ <!-- Templates will be dynamically loaded here -->
82
+ </div>
83
+ </div>
84
+ </div>
85
+ <div id="thoughts" style="display: none;">I've presented the user with a list of created pages.</div>
86
+ <div id="loadingOverlay" class="loading-overlay"><div class="spinner"></div></div>
87
+ <script>
88
+ // Basic chat functionality
89
+ document.getElementById("chatInput").focus();
90
+ document.getElementById("chatForm").addEventListener('submit', () => {
91
+ document.getElementById("loadingOverlay").style.display = 'flex';
92
+ document.getElementById("chatForm").action = window.location.pathname;
93
+ });
94
+ document.getElementById("saveLink").addEventListener("click", function() {
95
+ const pageName = prompt("Enter the name of the page to save as:");
96
+ if (pageName) {
97
+ window.location.href = `${window.location.pathname}/save?name=${encodeURIComponent(pageName)}`;
98
+ }
99
+ });
100
+ document.getElementById("resetLink").addEventListener("click", function() {
101
+ window.location.href = `${window.location.pathname}/reset`;
102
+ });
103
+ window.onload = function() {
104
+ const chatMessages = document.getElementById('chatMessages');
105
+ chatMessages.scrollTo({
106
+ top: chatMessages.scrollHeight,
107
+ behavior: 'smooth'
108
+ });
109
+ };
110
+
111
+ // Fetch custom pages and templates and display them
112
+ fetch('/api/pages')
113
+ .then(response => response.json())
114
+ .then(data => {
115
+ const customPagesList = document.getElementById('customPagesList');
116
+ const templatesList = document.getElementById('templatesList');
117
+ customPagesList.innerHTML = ''; // Clear existing content
118
+ templatesList.innerHTML = ''; // Clear existing content
119
+ const systemPages = ['home', 'pages', 'settings', 'apis', 'scripts'];
120
+ data.forEach(page => {
121
+ const pageLink = document.createElement('a');
122
+ pageLink.href = `/${page}`;
123
+ pageLink.textContent = page;
124
+ pageLink.className = 'page-link';
125
+ if (page.startsWith('[') && page.endsWith(']')) {
126
+ templatesList.appendChild(pageLink);
127
+ } else if (!systemPages.includes(page.toLowerCase())) {
128
+ customPagesList.appendChild(pageLink);
129
+ }
130
+ });
131
+ })
132
+ .catch(error => console.error('Error fetching pages:', error));
133
+ </script>
134
+ </body>
135
+ </html>