underpost 2.8.866 → 2.8.871

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 (42) hide show
  1. package/README.md +52 -36
  2. package/bin/build.js +1 -0
  3. package/bin/deploy.js +30 -1
  4. package/bin/file.js +3 -0
  5. package/bin/util.js +1 -56
  6. package/cli.md +88 -86
  7. package/conf.js +1 -1
  8. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  9. package/manifests/deployment/mongo-express/deployment.yaml +12 -12
  10. package/manifests/maas/nvim.sh +91 -0
  11. package/package.json +1 -10
  12. package/src/api/file/file.service.js +28 -8
  13. package/src/api/user/user.router.js +24 -0
  14. package/src/api/user/user.service.js +3 -4
  15. package/src/cli/cluster.js +2 -13
  16. package/src/cli/cron.js +0 -1
  17. package/src/cli/db.js +0 -19
  18. package/src/cli/deploy.js +17 -26
  19. package/src/cli/fs.js +1 -0
  20. package/src/cli/index.js +1 -0
  21. package/src/cli/run.js +9 -2
  22. package/src/client/components/core/CalendarCore.js +1 -1
  23. package/src/client/components/core/CssCore.js +12 -0
  24. package/src/client/components/core/Docs.js +2 -2
  25. package/src/client/components/core/FullScreen.js +19 -28
  26. package/src/client/components/core/Input.js +1 -0
  27. package/src/client/components/core/Modal.js +66 -63
  28. package/src/client/components/core/ObjectLayerEngine.js +229 -4
  29. package/src/client/components/core/ObjectLayerEngineModal.js +441 -0
  30. package/src/client/components/core/Panel.js +4 -1
  31. package/src/client/components/core/PanelForm.js +1 -1
  32. package/src/client/components/core/Router.js +29 -25
  33. package/src/client/components/core/ToggleSwitch.js +15 -1
  34. package/src/client/components/core/VanillaJs.js +12 -13
  35. package/src/client/public/default/assets/mailer/api-user-default-avatar.png +0 -0
  36. package/src/index.js +1 -1
  37. package/src/server/client-build.js +3 -11
  38. package/src/server/client-icons.js +6 -78
  39. package/src/server/conf.js +20 -64
  40. package/src/server/process.js +2 -1
  41. package/test/api.test.js +3 -2
  42. package/bin/cyberia0.js +0 -78
@@ -0,0 +1,441 @@
1
+ import { CoreService } from '../../services/core/core.service.js';
2
+ import { BtnIcon } from './BtnIcon.js';
3
+ import { borderChar, dynamicCol } from './Css.js';
4
+ import { DropDown } from './DropDown.js';
5
+ import { EventsUI } from './EventsUI.js';
6
+ import { Translate } from './Translate.js';
7
+ import { getProxyPath, s, append, hexToRgbA } from './VanillaJs.js';
8
+ import { s4 } from './CommonJs.js';
9
+ import { Input } from './Input.js';
10
+ import { ToggleSwitch } from './ToggleSwitch.js';
11
+ import { ObjectLayerService } from '../../services/object-layer/object-layer.service.js';
12
+
13
+ const ObjectLayerEngineModal = {
14
+ templates: [
15
+ {
16
+ label: 'empty',
17
+ id: 'empty',
18
+ data: [],
19
+ },
20
+ ],
21
+ RenderTemplate: (colorTemplate) => {
22
+ const ole = s('object-layer-engine');
23
+ if (!ole) {
24
+ return;
25
+ }
26
+
27
+ if (colorTemplate.length === 0) {
28
+ ole.clear();
29
+ return;
30
+ }
31
+
32
+ const matrix = colorTemplate.map((row) => row.map((hex) => [...hexToRgbA(hex), 255]));
33
+ ole.loadMatrix(matrix);
34
+ },
35
+ ObjectLayerData: {},
36
+ Render: async (options = { idModal: '' }) => {
37
+ await import(`${getProxyPath()}components/core/ObjectLayerEngine.js`);
38
+ // await import(`${getProxyPath()}components/core/WebComponent.js`);
39
+ const directionCodes = ['08', '18', '02', '12', '04', '14', '06', '16'];
40
+ const itemTypes = ['skin', 'weapon', 'armor', 'artifact', 'floor'];
41
+ const statTypes = ['effect', 'resistance', 'agility', 'range', 'intelligence', 'utility'];
42
+ let selectItemType = itemTypes[0];
43
+ let itemActivable = false;
44
+ let renderIsStateless = false;
45
+ let renderFrameDuration = 100;
46
+
47
+ for (const url of [
48
+ `${getProxyPath()}assets/templates/item-skin-08.json`,
49
+ `${getProxyPath()}assets/templates/item-skin-06.json`,
50
+ ]) {
51
+ const id = url.split('/').pop().replace('.json', '');
52
+ ObjectLayerEngineModal.templates.push({
53
+ label: id,
54
+ id,
55
+ data: JSON.parse(await CoreService.getRaw({ url })).color,
56
+ });
57
+ }
58
+
59
+ const cells = 26;
60
+ const pixelSize = parseInt(320 / cells);
61
+ const idSectionA = 'template-section-a';
62
+ const idSectionB = 'template-section-b';
63
+
64
+ let directionsCodeBarRender = '';
65
+
66
+ for (const directionCode of directionCodes) {
67
+ setTimeout(() => {
68
+ EventsUI.onClick(`.direction-code-bar-frames-btn-${directionCode}`, async () => {
69
+ const image = await s('object-layer-engine').toBlob();
70
+ const json = s('object-layer-engine').exportMatrixJSON();
71
+ const id = `frame-capture-${s4()}-${s4()}`;
72
+
73
+ if (!ObjectLayerEngineModal.ObjectLayerData[directionCode])
74
+ ObjectLayerEngineModal.ObjectLayerData[directionCode] = [];
75
+ ObjectLayerEngineModal.ObjectLayerData[directionCode].push({ id, image, json });
76
+
77
+ append(
78
+ `.frames-${directionCode}`,
79
+ html`
80
+ <div class="in fll ${id}">
81
+ <img class="in fll direction-code-bar-frames-img" src="${URL.createObjectURL(image)}" />
82
+ ${await BtnIcon.Render({
83
+ label: html`<i class="fa-solid fa-trash"></i>`,
84
+ class: `abs direction-code-bar-trash-btn direction-code-bar-trash-btn-${id}`,
85
+ })}
86
+ </div>
87
+ `,
88
+ );
89
+
90
+ EventsUI.onClick(`.direction-code-bar-trash-btn-${id}`, async () => {
91
+ s(`.${id}`).remove();
92
+ ObjectLayerEngineModal.ObjectLayerData[directionCode] = ObjectLayerEngineModal.ObjectLayerData[
93
+ directionCode
94
+ ].filter((frame) => frame.id !== id);
95
+ });
96
+ });
97
+
98
+ EventsUI.onClick(`.ol-btn-save`, async () => {
99
+ const objectLayer = {
100
+ data: {
101
+ render: {
102
+ frames: {},
103
+ color: [],
104
+ frame_duration: 0,
105
+ is_stateless: false,
106
+ },
107
+ stats: {},
108
+ item: {},
109
+ },
110
+ };
111
+ for (const directionCode of directionCodes) {
112
+ const directions = ObjectLayerEngineModal.getDirectionsFromDirectionCode(directionCode);
113
+ for (const direction of directions) {
114
+ if (!objectLayer.data.render.frames[direction]) objectLayer.data.render.frames[direction] = [];
115
+
116
+ if (!(directionCode in ObjectLayerEngineModal.ObjectLayerData)) {
117
+ console.warn('No set directionCodeBarFrameData for directionCode', directionCode);
118
+ continue;
119
+ }
120
+
121
+ for (const frameData of ObjectLayerEngineModal.ObjectLayerData[directionCode]) {
122
+ const { matrix } = JSON.parse(frameData.json);
123
+ const frameIndexColorMatrix = [];
124
+ let indexRow = -1;
125
+ for (const row of matrix) {
126
+ indexRow++;
127
+ frameIndexColorMatrix[indexRow] = [];
128
+ let indexCol = -1;
129
+ for (const value of row) {
130
+ indexCol++;
131
+ let colorIndex = objectLayer.data.render.color.findIndex(
132
+ (color) =>
133
+ color[0] === value[0] &&
134
+ color[1] === value[1] &&
135
+ color[2] === value[2] &&
136
+ color[3] === value[3],
137
+ );
138
+ if (colorIndex === -1) {
139
+ objectLayer.data.render.color.push(value);
140
+ colorIndex = objectLayer.data.render.color.length - 1;
141
+ }
142
+ frameIndexColorMatrix[indexRow][indexCol] = colorIndex;
143
+ }
144
+ }
145
+ objectLayer.data.render.frames[direction].push(frameIndexColorMatrix);
146
+ }
147
+ }
148
+ }
149
+ objectLayer.data.render.frame_duration = parseInt(s(`.ol-input-render-frame-duration`).value);
150
+ objectLayer.data.render.is_stateless = renderIsStateless;
151
+ objectLayer.data.stats = {
152
+ effect: parseInt(s(`.ol-input-item-stats-effect`).value),
153
+ resistance: parseInt(s(`.ol-input-item-stats-resistance`).value),
154
+ agility: parseInt(s(`.ol-input-item-stats-agility`).value),
155
+ range: parseInt(s(`.ol-input-item-stats-range`).value),
156
+ intelligence: parseInt(s(`.ol-input-item-stats-intelligence`).value),
157
+ utility: parseInt(s(`.ol-input-item-stats-utility`).value),
158
+ };
159
+ objectLayer.data.item = {
160
+ type: selectItemType,
161
+ activable: itemActivable,
162
+ id: s(`.ol-input-item-id`).value,
163
+ description: s(`.ol-input-item-description`).value,
164
+ };
165
+ console.warn('objectLayer', objectLayer);
166
+
167
+ // Upload images
168
+ {
169
+ for (const directionCode of Object.keys(ObjectLayerEngineModal.ObjectLayerData)) {
170
+ let frameIndex = -1;
171
+ for (const frame of ObjectLayerEngineModal.ObjectLayerData[directionCode]) {
172
+ frameIndex++;
173
+ const pngBlob = frame.image;
174
+
175
+ const form = new FormData();
176
+ form.append(directionCode, pngBlob, `${frameIndex}.png`);
177
+
178
+ const { status, data } = await ObjectLayerService.post({
179
+ id: `frame-image/${objectLayer.data.item.type}/${objectLayer.data.item.id}/${directionCode}`,
180
+ body: form,
181
+ headerId: 'file',
182
+ });
183
+ }
184
+ }
185
+ }
186
+
187
+ // Upload metadata
188
+ {
189
+ delete objectLayer.data.render.frames;
190
+ delete objectLayer.data.render.color;
191
+ const { status, data } = await ObjectLayerService.post({
192
+ id: `metadata/${objectLayer.data.item.type}/${objectLayer.data.item.id}`,
193
+ body: objectLayer,
194
+ });
195
+ }
196
+ });
197
+ });
198
+ directionsCodeBarRender += html`
199
+ <div class="in section-mp-border">
200
+ <div class="fl">
201
+ <div class="in fll">
202
+ <div class="in direction-code-bar-frames-title">${directionCode}</div>
203
+ <div class="in direction-code-bar-frames-btn">
204
+ ${await BtnIcon.Render({
205
+ label: html`<i class="fa-solid fa-plus"></i>`,
206
+ class: `direction-code-bar-frames-btn-${directionCode}`,
207
+ })}
208
+ </div>
209
+ </div>
210
+ <div class="frames-${directionCode}"></div>
211
+ </div>
212
+ </div>
213
+ `;
214
+ }
215
+
216
+ let statsInputsRender = '';
217
+ for (const statType of statTypes) {
218
+ statsInputsRender += html`
219
+ ${await Input.Render({
220
+ id: `ol-input-item-stats-${statType}`,
221
+ label: html`<div class="inl" style="width: 120px; font-size: 16px; overflow: hidden">
222
+ <i class="fa-solid fa-chart-simple"></i> ${statType}
223
+ </div>`,
224
+ containerClass: 'inl',
225
+ type: 'number',
226
+ min: 0,
227
+ max: 10,
228
+ placeholder: true,
229
+ value: 0,
230
+ })}
231
+ `;
232
+ }
233
+
234
+ return html`
235
+ <style>
236
+ .direction-code-bar-frames-title {
237
+ font-weight: bold;
238
+ font-size: 1.2rem;
239
+ padding: 0.5rem;
240
+ }
241
+ .direction-code-bar-frames-img {
242
+ width: 100px;
243
+ height: auto;
244
+ margin: 3px;
245
+ }
246
+ .direction-code-bar-trash-btn {
247
+ top: 3px;
248
+ left: 3px;
249
+ background: red;
250
+ color: white;
251
+ }
252
+ .ol-btn-save {
253
+ padding: 0.5rem;
254
+ font-size: 30px;
255
+ font-weight: bold;
256
+ }
257
+ .ol-number-label {
258
+ width: 120px;
259
+ font-size: 16px;
260
+ overflow: hidden;
261
+ font-family: 'retro-font';
262
+ }
263
+ .sub-title-modal {
264
+ color: #ffcc00;
265
+ }
266
+ </style>
267
+ ${borderChar(2, 'black', ['.sub-title-modal'])}
268
+
269
+ <div class="in section-mp section-mp-border">
270
+ <div class="in sub-title-modal"><i class="fa-solid fa-table-cells-large"></i> Frame editor</div>
271
+
272
+ <object-layer-engine id="ole" width="${cells}" height="${cells}" pixel-size="${pixelSize}">
273
+ </object-layer-engine>
274
+ </div>
275
+
276
+ <div class="in section-mp section-mp-border">
277
+ <div class="in sub-title-modal"><i class="fa-solid fa-database"></i> Render data</div>
278
+ ${dynamicCol({ containerSelector: options.idModal, id: idSectionA })}
279
+
280
+ <div class="fl">
281
+ <div class="in fll ${idSectionA}-col-a">
282
+ <div class="in section-mp">
283
+ ${await DropDown.Render({
284
+ value: ObjectLayerEngineModal.templates[0].id,
285
+ label: html`${Translate.Render('select-template')}`,
286
+ data: ObjectLayerEngineModal.templates.map((template) => {
287
+ return {
288
+ value: template.id,
289
+ display: html`<i class="fa-solid fa-paint-roller"></i> ${template.label}`,
290
+ onClick: async () => {
291
+ ObjectLayerEngineModal.RenderTemplate(template.data);
292
+ },
293
+ };
294
+ }),
295
+ })}
296
+ </div>
297
+ </div>
298
+ <div class="in fll ${idSectionA}-col-b">
299
+ <div class="in section-mp-border" style="width: 135px;">
300
+ ${await Input.Render({
301
+ id: `ol-input-render-frame-duration`,
302
+ label: html`<div class="inl ol-number-label">
303
+ <i class="fa-solid fa-chart-simple"></i> Frame duration
304
+ </div>`,
305
+ containerClass: 'inl',
306
+ type: 'number',
307
+ min: 100,
308
+ max: 1000,
309
+ placeholder: true,
310
+ value: renderFrameDuration,
311
+ })}
312
+ </div>
313
+ <div class="in section-mp">
314
+ ${await ToggleSwitch.Render({
315
+ id: 'ol-toggle-render-is-stateless',
316
+ wrapper: true,
317
+ wrapperLabel: html`${Translate.Render('is-stateless')}`,
318
+ disabledOnClick: true,
319
+ checked: renderIsStateless,
320
+ on: {
321
+ unchecked: () => {
322
+ renderIsStateless = false;
323
+ console.warn('renderIsStateless', renderIsStateless);
324
+ },
325
+ checked: () => {
326
+ renderIsStateless = true;
327
+ console.warn('renderIsStateless', renderIsStateless);
328
+ },
329
+ },
330
+ })}
331
+ </div>
332
+ </div>
333
+ </div>
334
+ ${directionsCodeBarRender}
335
+ </div>
336
+ ${dynamicCol({ containerSelector: options.idModal, id: idSectionB, type: 'a-50-b-50' })}
337
+
338
+ <div class="fl">
339
+ <div class="in fll ${idSectionB}-col-a">
340
+ <div class="in section-mp section-mp-border">
341
+ <div class="in sub-title-modal"><i class="fa-solid fa-database"></i> Item data</div>
342
+ ${await Input.Render({
343
+ id: `ol-input-item-id`,
344
+ label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.Render('item-id')}`,
345
+ containerClass: '',
346
+ placeholder: true,
347
+ })}
348
+ ${await Input.Render({
349
+ id: `ol-input-item-description`,
350
+ label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.Render('item-description')}`,
351
+ containerClass: '',
352
+ placeholder: true,
353
+ })}
354
+ <div class="in section-mp">
355
+ ${await DropDown.Render({
356
+ value: itemTypes[0],
357
+ label: html`${Translate.Render('select-item-type')}`,
358
+ data: itemTypes.map((itemType) => {
359
+ return {
360
+ value: itemType,
361
+ display: html`${itemType}`,
362
+ onClick: async () => {
363
+ console.warn('itemType click', itemType);
364
+ selectItemType = itemType;
365
+ },
366
+ };
367
+ }),
368
+ })}
369
+ </div>
370
+ <div class="in section-mp">
371
+ ${await ToggleSwitch.Render({
372
+ id: 'ol-toggle-item-activable',
373
+ wrapper: true,
374
+ wrapperLabel: html`${Translate.Render('item-activable')}`,
375
+ disabledOnClick: true,
376
+ checked: itemActivable,
377
+ on: {
378
+ unchecked: () => {
379
+ itemActivable = false;
380
+ console.warn('itemActivable', itemActivable);
381
+ },
382
+ checked: () => {
383
+ itemActivable = true;
384
+ console.warn('itemActivable', itemActivable);
385
+ },
386
+ },
387
+ })}
388
+ </div>
389
+ </div>
390
+ </div>
391
+ <div class="in fll ${idSectionB}-col-b">
392
+ <div class="in section-mp section-mp-border">
393
+ <div class="in sub-title-modal"><i class="fa-solid fa-database"></i> Stats data</div>
394
+ ${statsInputsRender}
395
+ </div>
396
+ </div>
397
+ </div>
398
+
399
+ <div class="in section-mp">
400
+ ${await BtnIcon.Render({
401
+ label: html`<i class="fa-solid fa-save"></i> ${Translate.Render('save')}`,
402
+ class: `in flr ol-btn-save`,
403
+ })}
404
+ </div>
405
+ `;
406
+ },
407
+ getDirectionsFromDirectionCode(directionCode = '08') {
408
+ let objectLayerFrameDirections = [];
409
+
410
+ switch (directionCode) {
411
+ case '08':
412
+ objectLayerFrameDirections = ['down_idle', 'none_idle', 'default_idle'];
413
+ break;
414
+ case '18':
415
+ objectLayerFrameDirections = ['down_walking'];
416
+ break;
417
+ case '02':
418
+ objectLayerFrameDirections = ['up_idle'];
419
+ break;
420
+ case '12':
421
+ objectLayerFrameDirections = ['up_walking'];
422
+ break;
423
+ case '04':
424
+ objectLayerFrameDirections = ['left_idle', 'up_left_idle', 'down_left_idle'];
425
+ break;
426
+ case '14':
427
+ objectLayerFrameDirections = ['left_walking', 'up_left_walking', 'down_left_walking'];
428
+ break;
429
+ case '06':
430
+ objectLayerFrameDirections = ['right_idle', 'up_right_idle', 'down_right_idle'];
431
+ break;
432
+ case '16':
433
+ objectLayerFrameDirections = ['right_walking', 'up_right_walking', 'down_right_walking'];
434
+ break;
435
+ }
436
+
437
+ return objectLayerFrameDirections;
438
+ },
439
+ };
440
+
441
+ export { ObjectLayerEngineModal };
@@ -12,7 +12,7 @@ import { dynamicCol, renderCssAttr } from './Css.js';
12
12
  import { EventsUI } from './EventsUI.js';
13
13
  import { ToggleSwitch } from './ToggleSwitch.js';
14
14
  import { Modal } from './Modal.js';
15
- import { RouterEvents } from './Router.js';
15
+ import { RouterEvents, setQueryPath } from './Router.js';
16
16
  import { RichText } from './RichText.js';
17
17
  import { loggerFactory } from './Logger.js';
18
18
  import { Badge } from './Badge.js';
@@ -473,6 +473,9 @@ const Panel = {
473
473
  setTimeout(() => {
474
474
  s(`.${idPanel}-form-body`).classList.add('hide');
475
475
  });
476
+ if (options.route && getQueryParams().cid) {
477
+ setQueryPath({ path: options.route, queryPath: '', replace: true });
478
+ }
476
479
  };
477
480
  s(`.btn-${idPanel}-add`).onclick = (e) => {
478
481
  e.preventDefault();
@@ -170,7 +170,7 @@ const PanelForm = {
170
170
  status,
171
171
  });
172
172
  if (getQueryParams().cid === data.id) {
173
- setQueryPath({ path: options.route, queryPath: '' });
173
+ setQueryPath({ path: options.route, queryPath: '', replace: true });
174
174
  if (PanelForm.Data[idPanel].updatePanel) await PanelForm.Data[idPanel].updatePanel();
175
175
  }
176
176
 
@@ -55,13 +55,13 @@ const LoadRouter = function (RouterInstance) {
55
55
  window.onpopstate = (e) => Router({ ...RouterInstance, e });
56
56
  };
57
57
 
58
- const setQueryPath = (options = { path: '', queryPath: '' }, queryKey = 'cid') => {
59
- const { queryPath, path } = options;
58
+ const setQueryPath = (options = { path: '', queryPath: '', replace: false }, queryKey = 'cid') => {
59
+ const { queryPath, path, replace } = options;
60
60
  const newUri = `${getProxyPath()}${path === 'home' ? '' : `${path}/`}${
61
- typeof queryPath === 'string' ? `?${queryKey}=${queryPath}` : ''
61
+ typeof queryPath === 'string' && queryPath ? `?${queryKey}=${queryPath}` : ''
62
62
  }`;
63
63
  const currentUri = `${window.location.pathname}${location.search}`;
64
- if (currentUri !== newUri && currentUri !== `${newUri}/`) setPath(newUri);
64
+ if (currentUri !== newUri && currentUri !== `${newUri}/`) setPath(newUri, {}, '', { replace });
65
65
  };
66
66
 
67
67
  const listenQueryPathInstance = ({ id, routeId, event }, queryKey = 'cid') => {
@@ -86,27 +86,31 @@ const triggerCloseModalRouteChangeEvents = (newPath) => {
86
86
  };
87
87
 
88
88
  const closeModalRouteChangeEvent = (options = {}) => {
89
- const { route, RouterInstance, homeCid } = options;
90
- if (!route) return;
91
-
92
- let path = window.location.pathname;
93
- if (path[path.length - 1] !== '/') path = `${path}/`;
94
- let newPath = `${getProxyPath()}`;
95
-
96
- if (path !== newPath) {
97
- for (const subIdModal of Object.keys(Modal.Data).reverse()) {
98
- if (Modal.Data[subIdModal]?.options?.route) {
99
- newPath = `${newPath}${Modal.Data[subIdModal].options.route}`;
100
- triggerCloseModalRouteChangeEvents(newPath);
101
- setPath(newPath);
102
- setDocTitle(newPath);
103
- Modal.setTopModalCallback(subIdModal);
104
- }
105
- }
106
- newPath = `${newPath}${homeCid ? `?cid=${homeCid}` : ''}`;
107
- triggerCloseModalRouteChangeEvents(newPath);
108
- setPath(newPath);
109
- setDocTitle(newPath);
89
+ const { closedId, homeCid } = options;
90
+ if (!closedId) return;
91
+
92
+ const remainingModals = Object.keys(Modal.Data).filter(
93
+ (id) => id !== closedId && (Modal.Data[id]?.options?.route || Modal.Data[id]?.options?.query),
94
+ );
95
+
96
+ const topModalId = remainingModals.reverse().find((id) => Modal.Data[id]);
97
+
98
+ if (topModalId) {
99
+ const topModal = Modal.Data[topModalId];
100
+ const route = topModal.options.route;
101
+ const query = topModal.query;
102
+ const path = route ? `${getProxyPath()}${route}` : location.pathname;
103
+ const newUrl = `${path}${query || ''}`;
104
+
105
+ triggerCloseModalRouteChangeEvents(newUrl);
106
+ setPath(newUrl, {}, '', { replace: true });
107
+ setDocTitle(route || path);
108
+ Modal.setTopModalCallback(topModalId);
109
+ } else {
110
+ const homeUrl = `${getProxyPath()}${homeCid ? `?cid=${homeCid}` : ''}`;
111
+ triggerCloseModalRouteChangeEvents(homeUrl);
112
+ setPath(homeUrl, {}, '', { replace: true });
113
+ setDocTitle('home');
110
114
  }
111
115
  };
112
116
 
@@ -67,7 +67,7 @@ const ToggleSwitch = {
67
67
 
68
68
  if (options.type === 'checkbox') {
69
69
  }
70
- return html`
70
+ const htmlRender = html`
71
71
  ${options?.displayMode === 'checkbox'
72
72
  ? html`<div class="${options?.containerClass ? options.containerClass : 'inl box-content-border'} ${id}">
73
73
  <div class="in ${id}-content toggle-switch-content-checkbox">
@@ -81,6 +81,20 @@ const ToggleSwitch = {
81
81
  </div>`}
82
82
  <input type="checkbox" class="${id}-checkbox" style="display: none" />
83
83
  `;
84
+ if (options.wrapper) {
85
+ setTimeout(() => (s(`.toggle-form-container-${id}`).onclick = () => ToggleSwitch.Tokens[`${id}`].click()));
86
+ return html`
87
+ <div class="in toggle-form-container toggle-form-container-${id} hover">
88
+ <div class="fl ">
89
+ <div class="in fll" style="width: 70%">
90
+ <div class="in">${options.wrapperLabel}</div>
91
+ </div>
92
+ <div class="in fll" style="width: 30%">${htmlRender}</div>
93
+ </div>
94
+ </div>
95
+ `;
96
+ }
97
+ return htmlRender;
84
98
  },
85
99
  };
86
100
 
@@ -144,9 +144,11 @@ const pasteData = () => new Promise((resolve) => navigator.clipboard.readText().
144
144
  * @param title - The `title` parameter in the `setPath` function is a string that represents the
145
145
  * title of the new history entry. It is used as the title of the new history entry in the browser's
146
146
  * history.
147
+ * @param {object} [options={}] - Additional options.
148
+ * @param {boolean} [options.replace=false] - If true, use `history.replaceState` instead of `history.pushState`.
147
149
  * @memberof VanillaJS
148
150
  */
149
- const setPath = (path = '/', stateStorage = {}, title = '') => {
151
+ const setPath = (path = '/', stateStorage = {}, title = '', options = {}) => {
150
152
  if (!path) path = '/';
151
153
 
152
154
  const [inputPath, inputSearch] = `${path}`.split('?');
@@ -159,28 +161,25 @@ const setPath = (path = '/', stateStorage = {}, title = '') => {
159
161
  if (sanitizedPath.length > 1 && sanitizedPath[sanitizedPath.length - 1] === '/')
160
162
  sanitizedPath = sanitizedPath.slice(0, -1);
161
163
 
162
- if (window.location.pathname === sanitizedPath && (!inputSearch || inputSearch === location.search)) {
164
+ const newFullPath = `${sanitizedPath}${inputSearch ? `?${inputSearch}` : location.search}${location.hash ?? ''}`;
165
+ const currentFullPath = `${window.location.pathname}${location.search}${location.hash}`;
166
+
167
+ if (currentFullPath === newFullPath) {
163
168
  console.warn('Prevent overwriting same path', {
164
- inputPath: inputPath,
165
- inputSearch: inputSearch,
166
- sanitizedPath: sanitizedPath,
167
- currentLocationSearch: location.search,
168
- currentLocationHash: location.hash,
169
+ newFullPath,
170
+ currentFullPath,
169
171
  });
170
172
  return;
171
173
  }
172
- console.warn('Set path', {
174
+ const historyMethod = options.replace ? history.replaceState : history.pushState;
175
+ console.warn(`Set path (${options.replace ? 'replace' : 'push'})`, {
173
176
  inputPath: inputPath,
174
177
  inputSearch: inputSearch,
175
178
  sanitizedPath: sanitizedPath,
176
179
  currentLocationSearch: location.search,
177
180
  currentLocationHash: location.hash,
178
181
  });
179
- return history.pushState(
180
- stateStorage,
181
- title,
182
- `${sanitizedPath}${inputSearch ? `?${inputSearch}` : ''}${location.hash ?? ''}`,
183
- );
182
+ return historyMethod.call(history, stateStorage, title, newFullPath);
184
183
  };
185
184
 
186
185
  /**
package/src/index.js CHANGED
@@ -35,7 +35,7 @@ class Underpost {
35
35
  * @type {String}
36
36
  * @memberof Underpost
37
37
  */
38
- static version = 'v2.8.866';
38
+ static version = 'v2.8.871';
39
39
  /**
40
40
  * Repository cli API
41
41
  * @static
@@ -19,7 +19,7 @@ import * as dir from 'path';
19
19
  import { shellExec } from './process.js';
20
20
  import { SitemapStream, streamToPromise } from 'sitemap';
21
21
  import { Readable } from 'stream';
22
- import { buildIcons, buildTextImg, getBufferPngText } from './client-icons.js';
22
+ import { buildIcons } from './client-icons.js';
23
23
  import Underpost from '../index.js';
24
24
  import { buildDocs } from './client-build-docs.js';
25
25
 
@@ -65,16 +65,8 @@ const fullBuild = async ({
65
65
  fs.removeSync(rootClientPath);
66
66
 
67
67
  if (fs.existsSync(`./src/client/public/${publicClientId}`)) {
68
- if (iconsBuild) {
69
- const defaultBaseIconFolderPath = `src/client/public/${publicClientId}/assets/logo`;
70
- if (!fs.existsSync(defaultBaseIconFolderPath)) fs.mkdirSync(defaultBaseIconFolderPath, { recursive: true });
71
- const defaultBaseIconPath = `${defaultBaseIconFolderPath}/base-icon.png`;
72
- if (!fs.existsSync(defaultBaseIconPath))
73
- await buildTextImg(metadata.title, { debugFilename: defaultBaseIconPath });
74
-
75
- if (!fs.existsSync(`./src/client/public/${publicClientId}/site.webmanifest`))
76
- await buildIcons({ publicClientId, metadata });
77
- }
68
+ if (iconsBuild === true) await buildIcons({ publicClientId, metadata });
69
+
78
70
  fs.copySync(
79
71
  `./src/client/public/${publicClientId}`,
80
72
  rootClientPath /* {