cyberia 3.0.2 → 3.1.3

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 (182) hide show
  1. package/{.env.production → .env.example} +20 -2
  2. package/.github/workflows/engine-cyberia.cd.yml +41 -10
  3. package/.github/workflows/engine-cyberia.ci.yml +53 -14
  4. package/.github/workflows/ghpkg.ci.yml +1 -1
  5. package/.github/workflows/gitlab.ci.yml +1 -1
  6. package/.github/workflows/hardhat.ci.yml +82 -0
  7. package/.github/workflows/npmpkg.ci.yml +37 -8
  8. package/.github/workflows/publish.ci.yml +5 -5
  9. package/.github/workflows/publish.cyberia.ci.yml +5 -5
  10. package/.github/workflows/pwa-microservices-template-page.cd.yml +3 -3
  11. package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
  12. package/.github/workflows/release.cd.yml +3 -2
  13. package/.vscode/extensions.json +9 -8
  14. package/.vscode/settings.json +3 -2
  15. package/CHANGELOG.md +533 -290
  16. package/CLI-HELP.md +79 -53
  17. package/WHITE-PAPER.md +1540 -0
  18. package/bin/build.js +16 -11
  19. package/bin/cyberia.js +959 -8
  20. package/bin/deploy.js +103 -270
  21. package/bin/file.js +2 -1
  22. package/bin/index.js +959 -8
  23. package/bin/vs.js +3 -3
  24. package/conf.js +277 -77
  25. package/deployment.yaml +218 -4
  26. package/hardhat/.env.example +31 -0
  27. package/hardhat/README.md +531 -0
  28. package/hardhat/WHITE-PAPER.md +1540 -0
  29. package/hardhat/contracts/ObjectLayerToken.sol +391 -0
  30. package/hardhat/deployments/.gitkeep +0 -0
  31. package/hardhat/deployments/hardhat-ObjectLayerToken.json +11 -0
  32. package/hardhat/hardhat.config.js +136 -0
  33. package/hardhat/ignition/modules/ObjectLayerToken.js +21 -0
  34. package/hardhat/networks/besu-object-layer.network.json +138 -0
  35. package/hardhat/package-lock.json +7628 -0
  36. package/hardhat/package.json +45 -0
  37. package/hardhat/scripts/deployObjectLayerToken.js +98 -0
  38. package/hardhat/test/ObjectLayerToken.js +590 -0
  39. package/jsdoc.dd-cyberia.json +59 -0
  40. package/jsdoc.json +20 -13
  41. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
  42. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
  43. package/manifests/deployment/dd-cyberia-development/deployment.yaml +490 -0
  44. package/manifests/deployment/dd-cyberia-development/proxy.yaml +261 -0
  45. package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +132 -0
  46. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  47. package/manifests/deployment/dd-test-development/deployment.yaml +52 -52
  48. package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
  49. package/manifests/pv-pvc-dd.yaml +1 -1
  50. package/package.json +60 -50
  51. package/proxy.yaml +128 -9
  52. package/pv-pvc.yaml +132 -0
  53. package/scripts/k3s-node-setup.sh +1 -1
  54. package/scripts/ports-ls.sh +2 -0
  55. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +3 -1
  56. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +1 -2
  57. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +40 -7
  58. package/src/api/document/document.service.js +1 -1
  59. package/src/api/file/file.controller.js +3 -1
  60. package/src/api/file/file.service.js +28 -5
  61. package/src/api/ipfs/ipfs.service.js +2 -2
  62. package/src/api/object-layer/object-layer.controller.js +6 -2
  63. package/src/api/object-layer/object-layer.model.js +67 -21
  64. package/src/api/object-layer/object-layer.router.js +668 -42
  65. package/src/api/object-layer/object-layer.service.js +10 -16
  66. package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +1 -2
  67. package/src/api/user/user.router.js +10 -5
  68. package/src/api/user/user.service.js +7 -7
  69. package/src/cli/baremetal.js +6 -10
  70. package/src/cli/cloud-init.js +0 -3
  71. package/src/cli/db.js +54 -71
  72. package/src/cli/deploy.js +64 -12
  73. package/src/cli/env.js +5 -5
  74. package/src/cli/fs.js +0 -2
  75. package/src/cli/image.js +0 -3
  76. package/src/cli/index.js +41 -13
  77. package/src/cli/monitor.js +5 -6
  78. package/src/cli/repository.js +329 -46
  79. package/src/cli/run.js +210 -122
  80. package/src/cli/secrets.js +1 -3
  81. package/src/cli/ssh.js +1 -1
  82. package/src/client/Itemledger.index.js +1 -959
  83. package/src/client/Underpost.index.js +36 -0
  84. package/src/client/components/core/AgGrid.js +20 -5
  85. package/src/client/components/core/Alert.js +2 -2
  86. package/src/client/components/core/Content.js +22 -3
  87. package/src/client/components/core/Docs.js +30 -6
  88. package/src/client/components/core/FileExplorer.js +71 -4
  89. package/src/client/components/core/Input.js +1 -1
  90. package/src/client/components/core/Modal.js +22 -6
  91. package/src/client/components/core/PublicProfile.js +3 -3
  92. package/src/client/components/core/RichText.js +1 -2
  93. package/src/client/components/core/Router.js +34 -1
  94. package/src/client/components/core/Worker.js +1 -1
  95. package/src/client/components/cryptokoyn/CssCryptokoyn.js +63 -1
  96. package/src/client/components/cyberia/ObjectLayerEngineModal.js +145 -119
  97. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +64 -6
  98. package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +1 -0
  99. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +44 -2
  100. package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +0 -1
  101. package/src/client/components/cyberia-portal/MenuCyberiaPortal.js +64 -2
  102. package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +1 -0
  103. package/src/client/components/itemledger/CssItemledger.js +62 -0
  104. package/src/client/components/underpost/CommonUnderpost.js +29 -0
  105. package/src/client/components/underpost/CssUnderpost.js +281 -0
  106. package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +879 -0
  107. package/src/client/components/underpost/DocumentSearchProvider.js +448 -0
  108. package/src/client/components/underpost/ElementsUnderpost.js +38 -0
  109. package/src/client/components/underpost/LabGalleryUnderpost.js +82 -0
  110. package/src/client/components/underpost/LogInUnderpost.js +23 -0
  111. package/src/client/components/underpost/LogOutUnderpost.js +15 -0
  112. package/src/client/components/underpost/MenuUnderpost.js +691 -0
  113. package/src/client/components/underpost/RoutesUnderpost.js +47 -0
  114. package/src/client/components/underpost/SettingsUnderpost.js +16 -0
  115. package/src/client/components/underpost/SignUpUnderpost.js +9 -0
  116. package/src/client/components/underpost/SocketIoUnderpost.js +54 -0
  117. package/src/client/components/underpost/TranslateUnderpost.js +10 -0
  118. package/src/client/public/cryptokoyn/assets/logo/base-icon.png +0 -0
  119. package/src/client/public/cryptokoyn/browserconfig.xml +12 -0
  120. package/src/client/public/cryptokoyn/microdata.json +85 -0
  121. package/src/client/public/cryptokoyn/site.webmanifest +57 -0
  122. package/src/client/public/cryptokoyn/sitemap +3 -3
  123. package/src/client/public/default/sitemap +3 -3
  124. package/src/client/public/itemledger/browserconfig.xml +2 -2
  125. package/src/client/public/itemledger/manifest.webmanifest +4 -4
  126. package/src/client/public/itemledger/microdata.json +71 -0
  127. package/src/client/public/itemledger/sitemap +3 -3
  128. package/src/client/public/itemledger/yandex-browser-manifest.json +2 -2
  129. package/src/client/public/test/sitemap +3 -3
  130. package/src/client/services/object-layer/object-layer.management.js +23 -4
  131. package/src/client/ssr/body/404.js +15 -11
  132. package/src/client/ssr/body/500.js +15 -11
  133. package/src/client/ssr/body/SwaggerDarkMode.js +285 -0
  134. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +83 -0
  135. package/src/client/ssr/head/PwaItemledger.js +60 -0
  136. package/src/client/ssr/head/UnderpostScripts.js +6 -0
  137. package/src/client/ssr/offline/NoNetworkConnection.js +11 -10
  138. package/src/client/ssr/pages/Test.js +11 -10
  139. package/src/client.build.js +0 -3
  140. package/src/client.dev.js +0 -3
  141. package/src/db/DataBaseProvider.js +17 -2
  142. package/src/db/mariadb/MariaDB.js +14 -9
  143. package/src/db/mongo/MongooseDB.js +17 -1
  144. package/src/index.js +1 -1
  145. package/src/proxy.js +0 -3
  146. package/src/runtime/express/Express.js +15 -9
  147. package/src/runtime/lampp/Lampp.js +6 -13
  148. package/src/server/auth.js +12 -14
  149. package/src/server/backup.js +2 -3
  150. package/src/server/besu-genesis-generator.js +1630 -0
  151. package/src/server/client-build-docs.js +126 -17
  152. package/src/server/client-build-live.js +9 -18
  153. package/src/server/client-build.js +203 -75
  154. package/src/server/client-dev-server.js +14 -13
  155. package/src/server/conf.js +376 -164
  156. package/src/server/cron.js +2 -1
  157. package/src/server/dns.js +28 -12
  158. package/src/server/downloader.js +0 -2
  159. package/src/server/logger.js +27 -9
  160. package/src/server/object-layer.js +92 -16
  161. package/src/server/peer.js +0 -2
  162. package/src/server/process.js +1 -50
  163. package/src/server/proxy.js +4 -8
  164. package/src/server/runtime.js +5 -8
  165. package/src/server/semantic-layer-generator.js +1 -0
  166. package/src/server/ssr.js +0 -3
  167. package/src/server/start.js +19 -12
  168. package/src/server/tls.js +0 -2
  169. package/src/server.js +0 -4
  170. package/.env.development +0 -43
  171. package/.env.test +0 -43
  172. package/hardhat/contracts/CryptoKoyn.sol +0 -59
  173. package/hardhat/contracts/ItemLedger.sol +0 -73
  174. package/hardhat/contracts/Lock.sol +0 -34
  175. package/hardhat/hardhat.config.cjs +0 -45
  176. package/hardhat/ignition/modules/Lock.js +0 -18
  177. package/hardhat/networks/cryptokoyn-itemledger.network.json +0 -29
  178. package/hardhat/scripts/deployCryptokoyn.cjs +0 -25
  179. package/hardhat/scripts/deployItemledger.cjs +0 -25
  180. package/hardhat/test/Lock.js +0 -126
  181. package/hardhat/white-paper.md +0 -581
  182. package/white-paper.md +0 -581
@@ -0,0 +1,448 @@
1
+ /**
2
+ * Document search provider for the SearchBox component.
3
+ * Provides typeahead search functionality for documents with custom rendering,
4
+ * click handling, and theme-aware styling.
5
+ * @module src/client/components/underpost/DocumentSearchProvider.js
6
+ * @namespace DocumentSearchProviderClient
7
+ */
8
+
9
+ import { loggerFactory } from '../core/Logger.js';
10
+ import { DocumentService } from '../../services/document/document.service.js';
11
+ import { Translate } from '../core/Translate.js';
12
+ import { getProxyPath } from '../core/Router.js';
13
+ import { Css, ThemeEvents, darkTheme, subThemeManager, lightenHex, darkenHex } from '../core/Css.js';
14
+ import { s } from '../core/VanillaJs.js';
15
+ import { Modal } from '../core/Modal.js';
16
+
17
+ const logger = loggerFactory(import.meta);
18
+
19
+ /**
20
+ * Document Search Provider singleton object for SearchBox integration.
21
+ * Implements the SearchBox provider interface with document-specific search,
22
+ * rendering, and interaction logic.
23
+ * @memberof DocumentSearchProviderClient
24
+ */
25
+ const DocumentSearchProvider = {
26
+ /**
27
+ * Unique identifier for this search provider.
28
+ * @type {string}
29
+ * @memberof DocumentSearchProviderClient.DocumentSearchProvider
30
+ */
31
+ id: 'document-search',
32
+
33
+ /**
34
+ * Priority level for search result ordering (lower number = higher priority).
35
+ * Higher priority than default routes (50).
36
+ * @type {number}
37
+ * @memberof DocumentSearchProviderClient.DocumentSearchProvider
38
+ */
39
+ priority: 10,
40
+
41
+ /**
42
+ * Searches documents using the high-query endpoint with optimized matching.
43
+ * Supports case-insensitive, multi-term, multi-field search for maximum results.
44
+ * Minimum query length: 1 character for maximum flexibility.
45
+ * Filters by idPanel tag to prevent out-of-panel context results.
46
+ * @memberof DocumentSearchProviderClient.DocumentSearchProvider
47
+ * @param {string} query - The search query string.
48
+ * @param {object} context - Search context object containing RouterInstance and options.
49
+ * @param {object} [context.RouterInstance] - Router instance for navigation.
50
+ * @param {object} [context.options] - Additional search options.
51
+ * @param {string} [context.idPanel] - Panel ID to filter documents by tag.
52
+ * @returns {Promise<Array<object>>} Promise resolving to array of search result objects.
53
+ * @returns {Promise<Array<{id: string, type: string, title: string, tags: Array<string>, createdAt: string, data: object}>>}
54
+ */
55
+ search: async (query, context) => {
56
+ // Minimum match requirement: allow 1 character for maximum results
57
+ if (!query || query.trim().length < 1) {
58
+ return [];
59
+ }
60
+
61
+ try {
62
+ const response = await DocumentService.high({
63
+ params: {
64
+ q: query.trim(),
65
+ idPanel: context.idPanel, // Filter by panel tag to prevent out-of-panel context results
66
+ limit: 7, // Increased limit for maximum results
67
+ },
68
+ });
69
+
70
+ if (response.status === 'success' && response.data && response.data.data) {
71
+ return response.data.data.map((doc) => ({
72
+ id: doc._id,
73
+ type: 'document',
74
+ title: doc.title || 'Untitled',
75
+ tags: doc.tags || [],
76
+ createdAt: doc.createdAt,
77
+ data: doc,
78
+ }));
79
+ }
80
+
81
+ return [];
82
+ } catch (error) {
83
+ logger.error('Document search error:', error);
84
+ return [];
85
+ }
86
+ },
87
+
88
+ /**
89
+ * Renders a custom result card for a document search result.
90
+ * Generates HTML with title, tags, date, and click handlers.
91
+ * @memberof DocumentSearchProviderClient.DocumentSearchProvider
92
+ * @param {object} result - The search result object to render.
93
+ * @param {string} result.id - Document ID.
94
+ * @param {string} result.type - Result type (should be 'document').
95
+ * @param {string} result.title - Document title.
96
+ * @param {Array<string>} result.tags - Document tags array.
97
+ * @param {string} result.createdAt - Document creation date.
98
+ * @param {object} result.data - Full document data object.
99
+ * @param {number} index - The index of this result in the results array.
100
+ * @param {object} context - Render context object.
101
+ * @returns {string} HTML string for the search result card.
102
+ */
103
+ renderResult: (result, index, context) => {
104
+ const title = result.title || 'Untitled';
105
+ const tags = result.tags || [];
106
+ const createdAt = result.createdAt ? new Date(result.createdAt).toLocaleDateString() : '';
107
+
108
+ // Check if document is public (from result.data.isPublic field)
109
+ const isPublic = result.data && result.data.isPublic === true;
110
+
111
+ // Visibility icon: globe for public, padlock for private
112
+ const visibilityIcon = isPublic
113
+ ? '<i class="fas fa-globe" title="Public document"></i>'
114
+ : '<i class="fas fa-lock" title="Private document"></i>';
115
+
116
+ // Build tags display with data attributes for click handling
117
+ const tagsHtml = tags
118
+ .filter((tag) => tag !== 'public')
119
+ .slice(0, 3)
120
+ .map((tag) => `<span class="document-search-tag" data-tag-value="${tag}">${tag}</span>`)
121
+ .join('');
122
+
123
+ // Attach tag handlers after rendering
124
+ setTimeout(() => {
125
+ DocumentSearchProvider.attachTagHandlers();
126
+ }, 50);
127
+
128
+ return html`
129
+ <div
130
+ class="search-result-item search-result-document"
131
+ data-result-id="${result.id}"
132
+ data-result-type="document"
133
+ data-result-index="${index}"
134
+ data-provider-id="document-search"
135
+ >
136
+ <div class="search-result-icon">
137
+ <i class="fas fa-file-alt"></i>
138
+ </div>
139
+ <div class="search-result-content">
140
+ <div class="search-result-title-row">
141
+ <span class="search-result-visibility-icon">${visibilityIcon}</span>
142
+ <span class="search-result-title">${title}</span>
143
+ </div>
144
+ <div class="search-result-meta">
145
+ ${createdAt ? `<span class="search-result-date">${createdAt}</span>` : ''}
146
+ ${tagsHtml ? `<div class="search-result-tags">${tagsHtml}</div>` : ''}
147
+ </div>
148
+ </div>
149
+ </div>
150
+ `;
151
+ },
152
+
153
+ /**
154
+ * Attaches click event handlers to tag elements in search results.
155
+ * When a tag is clicked, it populates the search box with the tag value
156
+ * and triggers a new search for that tag.
157
+ * @memberof DocumentSearchProviderClient.DocumentSearchProvider
158
+ * @returns {void}
159
+ */
160
+ attachTagHandlers: () => {
161
+ setTimeout(() => {
162
+ const tagElements = document.querySelectorAll('.document-search-tag');
163
+ tagElements.forEach((tagEl) => {
164
+ tagEl.onclick = (e) => {
165
+ e.stopPropagation();
166
+ e.preventDefault();
167
+
168
+ const tagValue = tagEl.getAttribute('data-tag-value') || tagEl.textContent.trim();
169
+
170
+ // Open search bar if closed
171
+ if (
172
+ !s('.main-body-btn-ui-bar-custom-open').classList.contains('hide') ||
173
+ !s(`.main-body-btn-ui-open`).classList.contains('hide')
174
+ )
175
+ s('.main-body-btn-bar-custom').click();
176
+
177
+ // Find and populate search box
178
+ const searchBox = s('.top-bar-search-box');
179
+ if (searchBox) {
180
+ searchBox.value = tagValue;
181
+ searchBox.focus();
182
+
183
+ // Trigger input event to start search
184
+ const inputEvent = new Event('input', { bubbles: true });
185
+ searchBox.dispatchEvent(inputEvent);
186
+
187
+ logger.info(`Document search tag clicked: ${tagValue}`);
188
+ }
189
+ };
190
+ });
191
+ }, 50);
192
+ },
193
+
194
+ /**
195
+ * Handles click events on document search results.
196
+ * Loads the selected document into the Underpost panel using SPA navigation.
197
+ * Prevents duplicate history entries if already viewing the same document.
198
+ * @memberof DocumentSearchProviderClient.DocumentSearchProvider
199
+ * @param {object} result - The search result object that was clicked.
200
+ * @param {string} result.id - Document ID to load.
201
+ * @param {string} result.title - Document title for logging.
202
+ * @param {object} context - Click context object with navigation helpers.
203
+ * @param {object} [context.RouterInstance] - Router instance for SPA navigation.
204
+ * @param {string} [context.currentRoute] - Current route name (e.g., 'home').
205
+ * @param {Function} [context.updatePanel] - Function to update the panel with new document.
206
+ * @returns {void}
207
+ */
208
+ onClick: async (result, context) => {
209
+ if (!result || !result.id) {
210
+ logger.warn('Invalid document result');
211
+ return;
212
+ }
213
+
214
+ logger.info(`Document clicked: ${result.id} - ${result.title}`);
215
+
216
+ // Close any open modal views (like Settings, Account, etc.) before navigating
217
+ // This ensures we return to home view when clicking a search result
218
+ await Modal.onHomeRouterEvent();
219
+
220
+ // Check if we're already on this document to prevent duplicate history
221
+ const currentUrl = new URL(window.location.href);
222
+ const currentCid = currentUrl.searchParams.get('cid');
223
+
224
+ // Only update URL and history if cid is different
225
+ if (currentCid !== result.id) {
226
+ // SPA Navigation: Update panel without page reload
227
+ const path = getProxyPath();
228
+ const queryPath = `?cid=${result.id}`;
229
+
230
+ // Update browser history without reload
231
+ window.history.pushState({}, '', `${path}${queryPath}`);
232
+
233
+ // Trigger PanelForm update with the document CID
234
+ if (context.updatePanel) context.updatePanel(result.id);
235
+ } else {
236
+ logger.info('Already on this document, not creating duplicate history');
237
+ }
238
+ },
239
+
240
+ /**
241
+ * Generates CSS styles for document search results with theme support.
242
+ * Uses subThemeManager colors for consistent theming across light and dark modes.
243
+ * Dynamically calculates colors based on current theme and subtheme settings.
244
+ * @memberof DocumentSearchProviderClient.DocumentSearchProvider
245
+ * @returns {string} CSS string containing all styles for document search results.
246
+ */
247
+ getStyles: () => {
248
+ // Get theme color from subThemeManager
249
+ const themeColor = darkTheme ? subThemeManager.darkColor : subThemeManager.lightColor;
250
+ const hasThemeColor = themeColor && themeColor !== null;
251
+
252
+ // Calculate theme-based colors
253
+ let borderColor, bgColor, hoverBg, hoverBorder, iconColor, textColor;
254
+ let tagBg, tagColor, tagHoverBg, activeBg, activeBorder;
255
+
256
+ if (darkTheme) {
257
+ // Dark theme styling
258
+ if (hasThemeColor) {
259
+ borderColor = darkenHex(themeColor, 0.75);
260
+ bgColor = darkenHex(themeColor, 0.85);
261
+ hoverBg = darkenHex(themeColor, 0.75);
262
+ hoverBorder = lightenHex(themeColor, 0.4);
263
+ iconColor = lightenHex(themeColor, 0.5);
264
+ textColor = lightenHex(themeColor, 0.8);
265
+ tagBg = darkenHex(themeColor, 0.6);
266
+ tagColor = lightenHex(themeColor, 0.7);
267
+ tagHoverBg = darkenHex(themeColor, 0.5);
268
+ activeBg = darkenHex(themeColor, 0.7);
269
+ activeBorder = lightenHex(themeColor, 0.3);
270
+ } else {
271
+ borderColor = '#444';
272
+ bgColor = '#2a2a2a';
273
+ hoverBg = '#333';
274
+ hoverBorder = '#0d6efd';
275
+ iconColor = '#aaa';
276
+ textColor = '#e0e0e0';
277
+ tagBg = '#4a4a4a';
278
+ tagColor = '#ffffff';
279
+ tagHoverBg = '#5a5a5a';
280
+ activeBg = '#333';
281
+ activeBorder = '#555';
282
+ }
283
+ } else {
284
+ // Light theme styling
285
+ if (hasThemeColor) {
286
+ borderColor = lightenHex(themeColor, 0.75);
287
+ bgColor = lightenHex(themeColor, 0.92);
288
+ hoverBg = lightenHex(themeColor, 0.85);
289
+ hoverBorder = lightenHex(themeColor, 0.5);
290
+ iconColor = darkenHex(themeColor, 0.3);
291
+ textColor = darkenHex(themeColor, 0.6);
292
+ tagBg = lightenHex(themeColor, 0.7);
293
+ tagColor = darkenHex(themeColor, 0.5);
294
+ tagHoverBg = lightenHex(themeColor, 0.6);
295
+ activeBg = lightenHex(themeColor, 0.85);
296
+ activeBorder = lightenHex(themeColor, 0.5);
297
+ } else {
298
+ borderColor = '#ddd';
299
+ bgColor = '#f9f9f9';
300
+ hoverBg = '#efefef';
301
+ hoverBorder = '#007bff';
302
+ iconColor = '#666';
303
+ textColor = '#333';
304
+ tagBg = '#a2a2a2';
305
+ tagColor = '#ffffff';
306
+ tagHoverBg = '#8a8a8a';
307
+ activeBg = '#e8e8e8';
308
+ activeBorder = '#999';
309
+ }
310
+ }
311
+
312
+ return css`
313
+ /* Unified with Panel card styles - theme consistent */
314
+ .search-result-document {
315
+ padding: 8px;
316
+ margin: 2px 0;
317
+ border-radius: 4px;
318
+ cursor: pointer;
319
+ transition: all 0.2s ease;
320
+ display: flex;
321
+ align-items: flex-start;
322
+ gap: 10px;
323
+ border: 1px solid ${borderColor};
324
+ background: ${bgColor};
325
+ text-align: left;
326
+ position: relative;
327
+ box-sizing: border-box;
328
+ width: 100%;
329
+ max-width: 100%;
330
+ }
331
+
332
+ .search-result-document:hover {
333
+ background: ${hoverBg};
334
+ border-color: ${hoverBorder};
335
+ }
336
+
337
+ .search-result-document .search-result-icon {
338
+ font-size: 18px;
339
+ color: ${iconColor};
340
+ padding-top: 2px;
341
+ min-width: 20px;
342
+ display: flex;
343
+ align-items: center;
344
+ justify-content: center;
345
+ }
346
+
347
+ .search-result-document .search-result-content {
348
+ flex: 1;
349
+ min-width: 0;
350
+ }
351
+
352
+ .search-result-document .search-result-title {
353
+ font-weight: 500;
354
+ font-size: 14px;
355
+ color: ${textColor};
356
+ margin-bottom: 4px;
357
+ overflow: hidden;
358
+ text-overflow: ellipsis;
359
+ white-space: nowrap;
360
+ }
361
+
362
+ .search-result-document .search-result-meta {
363
+ display: flex;
364
+ align-items: center;
365
+ gap: 8px;
366
+ flex-wrap: wrap;
367
+ }
368
+
369
+ .search-result-document .search-result-date {
370
+ font-size: 11px;
371
+ color: ${darkTheme ? '#999' : '#888'};
372
+ }
373
+
374
+ .search-result-document .search-result-tags {
375
+ display: flex;
376
+ gap: 4px;
377
+ flex-wrap: wrap;
378
+ }
379
+
380
+ .document-search-tag {
381
+ font-size: 10px;
382
+ padding: 2px 6px;
383
+ border-radius: 3px;
384
+ background: ${tagBg};
385
+ color: ${tagColor};
386
+ font-weight: 500;
387
+ cursor: pointer;
388
+ transition: all 0.2s ease;
389
+ margin: 3px;
390
+ display: inline-block;
391
+ border: 1px solid
392
+ ${hasThemeColor ? (darkTheme ? lightenHex(themeColor, 0.3) : lightenHex(themeColor, 0.6)) : 'transparent'};
393
+ }
394
+
395
+ .document-search-tag:hover {
396
+ background: ${tagHoverBg};
397
+ transform: scale(1.05);
398
+ }
399
+
400
+ .document-search-tag:active {
401
+ transform: scale(0.98);
402
+ }
403
+
404
+ .search-result-title-row {
405
+ display: flex;
406
+ align-items: center;
407
+ gap: 6px;
408
+ }
409
+
410
+ .search-result-visibility-icon {
411
+ display: inline-flex;
412
+ align-items: center;
413
+ font-size: 12px;
414
+ opacity: 0.7;
415
+ transition: opacity 0.2s ease;
416
+ flex-shrink: 0;
417
+ }
418
+
419
+ .search-result-visibility-icon .fa-globe,
420
+ .search-result-visibility-icon .fa-lock {
421
+ color: ${darkTheme ? '#999' : '#666'};
422
+ }
423
+
424
+ .search-result-document:hover .search-result-visibility-icon {
425
+ opacity: 1;
426
+ }
427
+
428
+ .search-result-title-row .search-result-title {
429
+ margin-bottom: 0;
430
+ }
431
+
432
+ .search-result-document.active-search-result,
433
+ .search-result-document.main-btn-menu-active {
434
+ background: ${activeBg};
435
+ border-color: ${activeBorder};
436
+ box-shadow: 0 0 0 1px ${activeBorder}66;
437
+ }
438
+
439
+ /* Active document tags have stronger accent */
440
+ .search-result-document.active-search-result .document-search-tag {
441
+ background: ${hasThemeColor ? (darkTheme ? darkenHex(themeColor, 0.5) : lightenHex(themeColor, 0.65)) : tagBg};
442
+ border-color: ${activeBorder};
443
+ }
444
+ `;
445
+ },
446
+ };
447
+
448
+ export { DocumentSearchProvider };
@@ -0,0 +1,38 @@
1
+ import { loggerFactory } from '../core/Logger.js';
2
+ import { BaseElement } from './CommonUnderpost.js';
3
+
4
+ const logger = loggerFactory(import.meta);
5
+
6
+ const ElementsUnderpost = {
7
+ Data: BaseElement(),
8
+ Interval: {},
9
+ LocalDataScope: {},
10
+ Init: function (options = { type: 'user', id: 'main', element: {} }) {
11
+ const { type, id, element } = options;
12
+ this.Data[type][id] = {
13
+ ...BaseElement()[type].main,
14
+ ...this.Data[type][id],
15
+ ...element,
16
+ };
17
+ if (!this.Interval[type]) this.Interval[type] = {};
18
+ if (!this.Interval[type][id]) this.Interval[type][id] = {};
19
+ if (!this.LocalDataScope[type]) this.LocalDataScope[type] = {};
20
+ if (!this.LocalDataScope[type][id])
21
+ this.LocalDataScope[type][id] = {
22
+ path: [],
23
+ };
24
+ },
25
+ removeAll: function () {
26
+ for (const type of Object.keys(this.Data)) {
27
+ for (const id of Object.keys(this.Data[type])) {
28
+ if (this.Interval[type] && this.Interval[type][id]) {
29
+ for (const interval of Object.keys(this.Interval[type][id])) clearInterval(this.Interval[type][id][interval]);
30
+ }
31
+ }
32
+ }
33
+ this.Interval = {};
34
+ this.Data = BaseElement();
35
+ },
36
+ };
37
+
38
+ export { ElementsUnderpost };
@@ -0,0 +1,82 @@
1
+ import { BtnIcon } from '../core/BtnIcon.js';
2
+ import { getId } from '../core/CommonJs.js';
3
+ import { Css, Themes } from '../core/Css.js';
4
+ import { Modal, renderViewTitle } from '../core/Modal.js';
5
+ import { listenQueryPathInstance, setQueryPath } from '../core/Router.js';
6
+ import { s } from '../core/VanillaJs.js';
7
+
8
+ const LabGalleryUnderpost = {
9
+ Tokens: {},
10
+ View: [
11
+ { title: '3D PLOT DEMO', path: '3dplotdemo' },
12
+ { title: 'PATH FINDING', path: 'pathfinding' },
13
+ { title: 'SURVIVAL BALL GAME', path: 'survival' },
14
+ { title: 'INFINITE LEVELS LABYRYNTH', path: 'laberinto' },
15
+ { title: 'VIRTUAL ROLL DICE', path: 'dice' },
16
+ { title: 'BOT VIRTUAL WORLD', path: 'bots' },
17
+ { title: 'CELLULAR AUTOMATA SIMULATOR', path: 'life' },
18
+ { title: 'VANILLAJS SNAKE', path: 'snake' },
19
+ ],
20
+ Render: async function () {
21
+ const id = getId(this.Tokens, 'lab-gallery-');
22
+ let render = '';
23
+ let i = -1;
24
+ for (const view of this.View) {
25
+ i++;
26
+ const viewLabId = `${id}-${i}`;
27
+ setTimeout(() => {
28
+ s(`.btn-${viewLabId}`).onclick = async () => {
29
+ const ModalId = `modal-${viewLabId}`;
30
+ const { barConfig } = await Themes[Css.currentTheme]();
31
+ setQueryPath({ path: 'lab-gallery', queryPath: view.path });
32
+ await Modal.Render({
33
+ barConfig,
34
+ title: renderViewTitle({
35
+ icon: html`<i class="fa-solid fa-photo-film"></i>`,
36
+ text: view.title,
37
+ }),
38
+ id: ModalId,
39
+ html: async () => {
40
+ const url = `https://underpost.net/${view.path}`;
41
+ return html` <iframe class="wfa iframe-gallery" src="${url}"> </iframe> `;
42
+ },
43
+ maximize: true,
44
+ mode: 'view',
45
+ slideMenu: 'modal-menu',
46
+ query: true,
47
+ });
48
+ };
49
+ });
50
+ render += html`
51
+ <style>
52
+ .iframe-gallery {
53
+ border: none;
54
+ min-height: 400px;
55
+ }
56
+ </style>
57
+ <div class="in">
58
+ ${await BtnIcon.Render({
59
+ class: `wfa btn-lab-gallery btn-${viewLabId}`,
60
+ label: html`<i class="fa-solid fa-arrow-up-right-from-square"></i> &nbsp &nbsp${view.title}`,
61
+ })}
62
+ </div>
63
+ <div class="in iframe-${viewLabId} hide"></div>
64
+ `;
65
+ }
66
+ listenQueryPathInstance({
67
+ id,
68
+ routeId: 'lab-gallery',
69
+ event: (path) => {
70
+ const indexView = this.View.findIndex((view) => view.path === path);
71
+ if (indexView > -1) {
72
+ const viewLabId = `${id}-${indexView}`;
73
+ if (s(`.btn-${viewLabId}`)) s(`.btn-${viewLabId}`).click();
74
+ }
75
+ },
76
+ });
77
+
78
+ return render;
79
+ },
80
+ };
81
+
82
+ export { LabGalleryUnderpost };
@@ -0,0 +1,23 @@
1
+ import { Auth } from '../core/Auth.js';
2
+ import { LogIn } from '../core/LogIn.js';
3
+ import { ElementsUnderpost } from './ElementsUnderpost.js';
4
+ import { PanelForm } from '../core/PanelForm.js';
5
+ import { RouterReady } from '../core/Router.js';
6
+ import { s } from '../core/VanillaJs.js';
7
+ import { commonUserGuard } from '../core/CommonJs.js';
8
+
9
+ const LogInUnderpost = async function () {
10
+ LogIn.Event['LogInUnderpost'] = async (options) => {
11
+ const { token, user } = options;
12
+
13
+ ElementsUnderpost.Data.user.main.model.user = user;
14
+
15
+ await RouterReady;
16
+ await PanelForm.Data['underpost-panel'].updatePanel();
17
+ if (s(`.main-btn-cloud`) && commonUserGuard(user.role)) s(`.main-btn-cloud`).classList.remove('hide');
18
+ };
19
+ const { user } = await Auth.sessionIn();
20
+ ElementsUnderpost.Data.user.main.model.user = user;
21
+ };
22
+
23
+ export { LogInUnderpost };
@@ -0,0 +1,15 @@
1
+ import { LogOut } from '../core/LogOut.js';
2
+ import { ElementsUnderpost } from './ElementsUnderpost.js';
3
+ import { PanelForm } from '../core/PanelForm.js';
4
+ import { s } from '../core/VanillaJs.js';
5
+
6
+ const LogOutUnderpost = async function () {
7
+ LogOut.Event['LogOutUnderpost'] = async (result = { user: { _id: '' } }) => {
8
+ ElementsUnderpost.Data.user.main.model.user = result.user;
9
+
10
+ PanelForm.Data['underpost-panel'].updatePanel();
11
+ if (s(`.main-btn-cloud`)) s(`.main-btn-cloud`).classList.add('hide');
12
+ };
13
+ };
14
+
15
+ export { LogOutUnderpost };