underpost 2.8.84 → 2.8.86

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 (128) hide show
  1. package/.env.development +1 -0
  2. package/.env.production +1 -0
  3. package/.env.test +1 -0
  4. package/.github/workflows/{ghpkg.yml → ghpkg.ci.yml} +1 -1
  5. package/.github/workflows/{npmpkg.yml → npmpkg.ci.yml} +1 -1
  6. package/.github/workflows/{publish.yml → publish.ci.yml} +1 -1
  7. package/.github/workflows/{pwa-microservices-template.page.yml → pwa-microservices-template-page.cd.yml} +2 -2
  8. package/.github/workflows/{pwa-microservices-template.test.yml → pwa-microservices-template-test.ci.yml} +1 -1
  9. package/.github/workflows/release.cd.yml +37 -0
  10. package/.vscode/settings.json +0 -1
  11. package/README.md +16 -10
  12. package/bin/build.js +15 -5
  13. package/bin/cyberia0.js +78 -0
  14. package/bin/db.js +1 -3
  15. package/bin/deploy.js +29 -431
  16. package/bin/file.js +26 -9
  17. package/cli.md +102 -61
  18. package/conf.js +1 -1
  19. package/manifests/deployment/{dd-template-development → dd-default-development}/deployment.yaml +16 -16
  20. package/manifests/deployment/{dd-template-development → dd-default-development}/proxy.yaml +3 -3
  21. package/manifests/grafana/deployment.yaml +57 -0
  22. package/manifests/grafana/kustomization.yaml +7 -0
  23. package/manifests/grafana/pvc.yaml +12 -0
  24. package/manifests/grafana/service.yaml +14 -0
  25. package/manifests/maas/gpu-diag.sh +1 -1
  26. package/manifests/maas/ssh-cluster-info.sh +14 -0
  27. package/manifests/prometheus/deployment.yaml +82 -0
  28. package/package.json +4 -7
  29. package/src/api/user/user.router.js +24 -1
  30. package/src/api/user/user.service.js +9 -38
  31. package/src/cli/cluster.js +83 -29
  32. package/src/cli/cron.js +12 -45
  33. package/src/cli/db.js +149 -0
  34. package/src/cli/deploy.js +40 -81
  35. package/src/cli/index.js +29 -6
  36. package/src/cli/monitor.js +9 -16
  37. package/src/cli/repository.js +12 -5
  38. package/src/cli/run.js +175 -7
  39. package/src/cli/ssh.js +32 -0
  40. package/src/client/Default.index.js +7 -5
  41. package/src/client/components/core/Account.js +7 -3
  42. package/src/client/components/core/Chat.js +1 -1
  43. package/src/client/components/core/CommonJs.js +24 -22
  44. package/src/client/components/core/Content.js +12 -12
  45. package/src/client/components/core/Css.js +262 -18
  46. package/src/client/components/core/CssCore.js +8 -8
  47. package/src/client/components/core/Docs.js +14 -61
  48. package/src/client/components/core/DropDown.js +137 -82
  49. package/src/client/components/core/EventsUI.js +92 -5
  50. package/src/client/components/core/Input.js +6 -1
  51. package/src/client/components/core/LoadingAnimation.js +8 -15
  52. package/src/client/components/core/LogIn.js +3 -0
  53. package/src/client/components/core/LogOut.js +1 -1
  54. package/src/client/components/core/Modal.js +601 -137
  55. package/src/client/components/core/NotificationManager.js +2 -2
  56. package/src/client/components/core/ObjectLayerEngine.js +638 -0
  57. package/src/client/components/core/Panel.js +158 -34
  58. package/src/client/components/core/PanelForm.js +12 -3
  59. package/src/client/components/core/Recover.js +6 -3
  60. package/src/client/components/core/Router.js +77 -17
  61. package/src/client/components/core/Scroll.js +65 -120
  62. package/src/client/components/core/SignUp.js +1 -0
  63. package/src/client/components/core/SocketIo.js +3 -3
  64. package/src/client/components/core/Translate.js +6 -2
  65. package/src/client/components/core/VanillaJs.js +48 -5
  66. package/src/client/components/core/Worker.js +3 -1
  67. package/src/client/components/default/CssDefault.js +17 -3
  68. package/src/client/components/default/MenuDefault.js +266 -47
  69. package/src/client/components/default/RoutesDefault.js +8 -14
  70. package/src/client/public/default/android-chrome-144x144.png +0 -0
  71. package/src/client/public/default/android-chrome-192x192.png +0 -0
  72. package/src/client/public/default/android-chrome-256x256.png +0 -0
  73. package/src/client/public/default/android-chrome-36x36.png +0 -0
  74. package/src/client/public/default/android-chrome-48x48.png +0 -0
  75. package/src/client/public/default/android-chrome-72x72.png +0 -0
  76. package/src/client/public/default/android-chrome-96x96.png +0 -0
  77. package/src/client/public/default/apple-touch-icon-114x114-precomposed.png +0 -0
  78. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  79. package/src/client/public/default/apple-touch-icon-120x120-precomposed.png +0 -0
  80. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  81. package/src/client/public/default/apple-touch-icon-144x144-precomposed.png +0 -0
  82. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  83. package/src/client/public/default/apple-touch-icon-152x152-precomposed.png +0 -0
  84. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  85. package/src/client/public/default/apple-touch-icon-180x180-precomposed.png +0 -0
  86. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  87. package/src/client/public/default/apple-touch-icon-57x57-precomposed.png +0 -0
  88. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  89. package/src/client/public/default/apple-touch-icon-60x60-precomposed.png +0 -0
  90. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  91. package/src/client/public/default/apple-touch-icon-72x72-precomposed.png +0 -0
  92. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  93. package/src/client/public/default/apple-touch-icon-76x76-precomposed.png +0 -0
  94. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  95. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  96. package/src/client/public/default/apple-touch-icon.png +0 -0
  97. package/src/client/public/default/assets/background/dark.jpg +0 -0
  98. package/src/client/public/default/assets/background/dark.svg +557 -0
  99. package/src/client/public/default/assets/logo/base-icon.png +0 -0
  100. package/src/client/public/default/assets/logo/underpost.gif +0 -0
  101. package/src/client/public/default/assets/mailer/api-user-check.png +0 -0
  102. package/src/client/public/default/assets/mailer/api-user-invalid-token.png +0 -0
  103. package/src/client/public/default/assets/mailer/api-user-recover.png +0 -0
  104. package/src/client/public/default/favicon-16x16.png +0 -0
  105. package/src/client/public/default/favicon-32x32.png +0 -0
  106. package/src/client/public/default/favicon.ico +0 -0
  107. package/src/client/public/default/mstile-144x144.png +0 -0
  108. package/src/client/public/default/mstile-150x150.png +0 -0
  109. package/src/client/public/default/mstile-310x150.png +0 -0
  110. package/src/client/public/default/mstile-310x310.png +0 -0
  111. package/src/client/public/default/mstile-70x70.png +0 -0
  112. package/src/client/public/default/safari-pinned-tab.svg +24 -0
  113. package/src/client/ssr/body/DefaultSplashScreen.js +2 -2
  114. package/src/index.js +9 -1
  115. package/src/mailer/MailerProvider.js +37 -0
  116. package/src/monitor.js +24 -0
  117. package/src/runtime/lampp/Dockerfile +30 -39
  118. package/src/runtime/lampp/Lampp.js +11 -2
  119. package/src/server/client-build-docs.js +205 -0
  120. package/src/server/client-build-live.js +1 -1
  121. package/src/server/client-build.js +16 -166
  122. package/src/server/client-dev-server.js +1 -1
  123. package/src/server/conf.js +14 -277
  124. package/src/server/proxy.js +1 -2
  125. package/src/server/start.js +3 -3
  126. package/src/server/valkey.js +102 -41
  127. package/docker-compose.yml +0 -67
  128. package/prometheus.yml +0 -36
@@ -10,7 +10,7 @@ import { Modal } from './Modal.js';
10
10
  import { NotificationManager } from './NotificationManager.js';
11
11
  import { Translate } from './Translate.js';
12
12
  import { Validator } from './Validator.js';
13
- import { append, htmls, s } from './VanillaJs.js';
13
+ import { append, getProxyPath, htmls, s } from './VanillaJs.js';
14
14
 
15
15
  const Account = {
16
16
  UpdateEvent: {},
@@ -44,7 +44,7 @@ const Account = {
44
44
  { model: 'email', id: `account-email`, rules: [{ type: 'isEmpty' }, { type: 'isEmail' }] },
45
45
  {
46
46
  model: 'password',
47
- defaultValue: '*******',
47
+ defaultValue: '#Changethis123',
48
48
  id: `account-password`,
49
49
  rules: [{ type: 'isStrongPassword' }],
50
50
  },
@@ -103,7 +103,11 @@ const Account = {
103
103
  e.preventDefault();
104
104
  const result = await UserService.post({
105
105
  id: 'mailer/verify-email',
106
- body: { email: s(`.account-email`).value },
106
+ body: {
107
+ email: s(`.account-email`).value,
108
+ hostname: `${location.hostname}`,
109
+ proxyPath: getProxyPath(),
110
+ },
107
111
  });
108
112
  NotificationManager.Push({
109
113
  html: result.status === 'error' ? result.message : Translate.Render(`email send`),
@@ -53,7 +53,7 @@ const Chat = {
53
53
  html`
54
54
  <div class="in">
55
55
  <span class="chat-message-header">${getIsoDate(new Date())} | ${id}:</span><br />
56
- ${message}
56
+ <span class="chat-message-body"> ${message}</span>
57
57
  </div>
58
58
  `,
59
59
  );
@@ -822,70 +822,72 @@ const generateRandomPasswordSelection = (length) => {
822
822
 
823
823
  const commitData = {
824
824
  feat: {
825
- description: 'A new feature',
825
+ description: 'New feature or enhancement (frontend, backend, API, or UX)',
826
826
  title: 'Features',
827
827
  emoji: '✨',
828
828
  },
829
829
  fix: {
830
- description: 'A bug fix',
830
+ description: 'Fix a bug',
831
831
  title: 'Bug Fixes',
832
832
  emoji: '🐛',
833
833
  },
834
834
  docs: {
835
- description: 'Documentation only changes',
835
+ description: 'Documentation changes',
836
836
  title: 'Documentation',
837
837
  emoji: '📚',
838
838
  },
839
839
  style: {
840
- description:
841
- 'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)',
840
+ description: 'Formatting, whitespace, semicolons, code style',
842
841
  title: 'Styles',
843
842
  emoji: '💎',
844
843
  },
845
844
  refactor: {
846
- description: 'A code change that neither fixes a bug nor adds a feature',
845
+ description: 'Code refactor.',
847
846
  title: 'Code Refactoring',
848
847
  emoji: '📦',
849
848
  },
850
849
  perf: {
851
- description: 'A code change that improves performance',
850
+ description: 'Performance improvements across the stack.',
852
851
  title: 'Performance Improvements',
853
852
  emoji: '⚡️',
854
853
  },
854
+ ci: {
855
+ description: 'CI pipeline changes (GitHub Actions, runners, caching)',
856
+ title: 'Continuous Integration',
857
+ emoji: '⚙️',
858
+ },
855
859
  cd: {
856
- description:
857
- 'Changes to our Continuous Delivery configuration files and scripts (example scopes: Jenkins, Spinnaker, ArgoCD)',
860
+ description: 'CD / deployment changes (Remote ssh deployment scripts)',
858
861
  title: 'Continuous Delivery',
859
862
  emoji: '🚀',
860
863
  },
861
- test: {
862
- description: 'Adding missing tests or correcting existing tests',
863
- title: 'Tests',
864
- emoji: '🚨',
864
+ infra: {
865
+ description: 'Infrastructure changes (MAAS, LXD, cloud infra, networking, provisioning).',
866
+ title: 'Infrastructure',
867
+ emoji: '🏗️',
865
868
  },
866
869
  build: {
867
- description: 'Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)',
870
+ description: 'Build system or dependency changes (tooling, bundler, build scripts).',
868
871
  title: 'Builds',
869
872
  emoji: '🛠',
870
873
  },
871
- ci: {
872
- description:
873
- 'Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)',
874
- title: 'Continuous Integrations',
875
- emoji: '⚙️',
874
+ test: {
875
+ description: 'Unit or integration tests added/updated, test helpers, flake fixes.',
876
+ title: 'Tests',
877
+ emoji: '🚨',
876
878
  },
877
879
  chore: {
878
- description: "Other changes that don't modify src or test files",
880
+ description: "Other changes that don't modify src or tests (automation, housekeeping).",
879
881
  title: 'Chores',
880
882
  emoji: '♻️',
881
883
  },
882
884
  revert: {
883
- description: 'Reverts a previous commit',
885
+ description: 'Revert a previous commit or change.',
884
886
  title: 'Reverts',
885
887
  emoji: '🗑',
886
888
  },
887
889
  backup: {
888
- description: 'Changes related to backups, including creation, restoration, and maintenance.',
890
+ description: 'Backups, snapshotting, restore scripts, or backup docs.',
889
891
  title: 'Backups',
890
892
  emoji: '💾',
891
893
  },
@@ -7,7 +7,7 @@ import { Modal, renderViewTitle } from './Modal.js';
7
7
  import { DocumentService } from '../../services/document/document.service.js';
8
8
  import { CoreService, getApiBaseUrl } from '../../services/core/core.service.js';
9
9
  import { loggerFactory } from './Logger.js';
10
- import { imageShimmer, renderCssAttr } from './Css.js';
10
+ import { imageShimmer, renderChessPattern, renderCssAttr, styleFactory } from './Css.js';
11
11
 
12
12
  const logger = loggerFactory(import.meta);
13
13
 
@@ -105,7 +105,6 @@ const Content = {
105
105
  class: '',
106
106
  container: '',
107
107
  url: '',
108
- aHrefOptions: { disable: false },
109
108
  raw: false,
110
109
  },
111
110
  ) {
@@ -115,7 +114,6 @@ const Content = {
115
114
  width: '100%',
116
115
  border: 'none',
117
116
  };
118
- options.style = `style="${renderCssAttr(options)}"`;
119
117
  if (!options.class) options.class = ``;
120
118
  const { container, file } = options;
121
119
  const ext = file.name.split('.')[file.name.split('.').length - 1];
@@ -127,7 +125,7 @@ const Content = {
127
125
  const content = options.url
128
126
  ? await CoreService.getRaw({ url: options.url })
129
127
  : await getRawContentFile(getBlobFromUint8ArrayFile(file.data.data, file.mimetype));
130
- render += html`<div class="${options.class}" ${options.style}>${marked.parse(content)}</div>`;
128
+ render += html`<div class="${options.class}" ${styleFactory(options.style)}>${marked.parse(content)}</div>`;
131
129
  }
132
130
 
133
131
  break;
@@ -136,17 +134,19 @@ const Content = {
136
134
  case 'jpeg':
137
135
  case 'webp':
138
136
  case 'svg':
137
+ case 'gif':
139
138
  case 'png': {
140
139
  const url = options.url
141
140
  ? options.url
142
141
  : file._id
143
142
  ? getApiBaseUrl({ id: file._id, endpoint: 'file/blob' })
144
143
  : URL.createObjectURL(getBlobFromUint8ArrayFile(file.data.data, file.mimetype));
145
- const imgRender = html`<img class="in ${options.class}" ${options.style} src="${url}" />`;
146
- render += html`${options.aHrefOptions?.disable
147
- ? imgRender
148
- : html`<a href="${url}" target="_top">${imgRender}</a>`}`;
149
-
144
+ const imgRender = html`<img
145
+ class="in ${options.class}"
146
+ ${styleFactory(options.style, `${renderChessPattern(50)}`)}
147
+ src="${url}"
148
+ />`;
149
+ render += imgRender;
150
150
  break;
151
151
  }
152
152
  case 'pdf': {
@@ -157,14 +157,14 @@ const Content = {
157
157
  : URL.createObjectURL(getBlobFromUint8ArrayFile(file.data.data, file.mimetype));
158
158
  render += html`<iframe
159
159
  class="in ${options.class} iframe-${options.idModal}"
160
- ${options.style}
160
+ ${styleFactory(options.style)}
161
161
  src="${url}"
162
162
  ></iframe>`;
163
163
  break;
164
164
  }
165
165
 
166
166
  case 'json':
167
- render += html`<pre class="in ${options.class}" ${options.style}>
167
+ render += html`<pre class="in ${options.class}" ${styleFactory(options.style)}>
168
168
  ${JSON.stringify(
169
169
  JSON.parse(
170
170
  options.url
@@ -178,7 +178,7 @@ const Content = {
178
178
  break;
179
179
 
180
180
  default:
181
- render += html`<div class="in ${options.class}" ${options.style}>
181
+ render += html`<div class="in ${options.class}" ${styleFactory(options.style)}>
182
182
  ${options.url
183
183
  ? await CoreService.getRaw({ url: options.url })
184
184
  : await getRawContentFile(getBlobFromUint8ArrayFile(file.data.data, file.mimetype))}
@@ -1,9 +1,9 @@
1
- import { getId, newInstance, range, s4, splitEveryXChar } from './CommonJs.js';
1
+ import { getId, newInstance, range, rgbToHex, s4, splitEveryXChar } from './CommonJs.js';
2
2
  import { CssCoreDark, CssCoreLight } from './CssCore.js';
3
3
  import { DropDown } from './DropDown.js';
4
4
  import { Modal } from './Modal.js';
5
5
  import { Translate } from './Translate.js';
6
- import { append, getProxyPath, htmls, s } from './VanillaJs.js';
6
+ import { append, getProxyPath, htmls, s, sa } from './VanillaJs.js';
7
7
 
8
8
  let ThemesScope = [];
9
9
 
@@ -12,14 +12,47 @@ let ThemesScope = [];
12
12
  // https://www.1001fonts.com/
13
13
 
14
14
  const Css = {
15
+ // Menu button container transition styles
16
+ menuButtonContainer: () => css`
17
+ .main-btn-menu {
18
+ transition: all 0.2s ease-in-out;
19
+ position: relative;
20
+ }
21
+
22
+ .main-btn-menu::after {
23
+ content: '';
24
+ position: absolute;
25
+ bottom: 0;
26
+ left: 50%;
27
+ width: 0;
28
+ height: 2px;
29
+ background: currentColor;
30
+ transition: all 0.2s ease-in-out;
31
+ transform: translateX(-50%);
32
+ }
33
+
34
+ .main-btn-menu:hover::after {
35
+ width: 60%;
36
+ }
37
+
38
+ .main-btn-menu.active {
39
+ background: rgba(255, 255, 255, 0.1);
40
+ }
41
+
42
+ .main-btn-menu.active::after {
43
+ width: 80%;
44
+ background: currentColor;
45
+ }
46
+ `,
47
+
15
48
  loadThemes: async function (themes = []) {
16
49
  ThemesScope = [];
17
50
  for (const themeOptions of themes) addTheme(themeOptions);
18
51
  // if (!ThemesScope.find((t) => t.dark)) addTheme(CssCoreDark);
19
52
  // if (!ThemesScope.find((t) => !t.dark)) addTheme(CssCoreLight);
20
53
  if (ThemesScope.length === 0) {
21
- addTheme(CssCoreDark);
22
54
  addTheme(CssCoreLight);
55
+ addTheme(CssCoreDark);
23
56
  }
24
57
  const localStorageTheme = localStorage.getItem('_theme');
25
58
  if (localStorageTheme && Themes[localStorageTheme]) {
@@ -31,6 +64,16 @@ const Css = {
31
64
  Init: async function (options) {
32
65
  if (!options) options = ThemesScope[0];
33
66
  const { theme } = options;
67
+
68
+ // Inject menu button container styles
69
+ const styleId = 'menu-btn-container-styles';
70
+ if (!document.getElementById(styleId)) {
71
+ const style = document.createElement('style');
72
+ style.id = styleId;
73
+ style.textContent = this.menuButtonContainer();
74
+ document.head.appendChild(style);
75
+ }
76
+
34
77
  return await Themes[theme](options);
35
78
  },
36
79
  RenderSetting: async function () {
@@ -156,6 +199,7 @@ const addTheme = (options) => {
156
199
  if (!['core', 'css-core'].includes(options.theme))
157
200
  render += darkTheme ? await CssCoreDark.render() : await CssCoreLight.render();
158
201
  render += await options.render();
202
+ render += await subThemeManager.render();
159
203
  htmls('.theme', render);
160
204
  TriggerThemeEvents();
161
205
  }
@@ -169,13 +213,13 @@ const addTheme = (options) => {
169
213
  };
170
214
  };
171
215
 
172
- const borderChar = (px, color, selectors) => {
216
+ const borderChar = (px, color, selectors, hover = false) => {
173
217
  if (selectors) {
174
218
  return selectors
175
219
  .map(
176
220
  (selector) => html`
177
221
  <style>
178
- ${selector} {
222
+ ${selector}${hover ? ':hover' : ''} {
179
223
  text-shadow: ${px}px -${px}px ${px}px ${color}, -${px}px ${px}px ${px}px ${color},
180
224
  -${px}px -${px}px ${px}px ${color}, ${px}px ${px}px ${px}px ${color};
181
225
  }
@@ -189,18 +233,29 @@ const borderChar = (px, color, selectors) => {
189
233
  ${color}, ${px}px ${px}px ${px}px ${color};
190
234
  `;
191
235
  };
192
-
193
236
  const boxShadow = ({ selector }) => html`
194
- <style>
195
- ${selector} {
196
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
197
- }
198
- ${selector}:hover {
199
- box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 10px 30px 0 rgba(0, 0, 0, 0.3);
200
- }
201
- </style>
237
+ ${darkTheme
238
+ ? html`
239
+ <style>
240
+ ${selector} {
241
+ box-shadow: 0 4px 8px 0 rgba(255, 255, 255, 0.1), 0 6px 20px 0 rgba(255, 255, 255, 0.08);
242
+ }
243
+ ${selector}:hover {
244
+ box-shadow: 0 8px 16px 0 rgba(255, 255, 255, 0.15), 0 10px 30px 0 rgba(255, 255, 255, 0.1);
245
+ }
246
+ </style>
247
+ `
248
+ : html`
249
+ <style>
250
+ ${selector} {
251
+ box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
252
+ }
253
+ ${selector}:hover {
254
+ box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 10px 30px 0 rgba(0, 0, 0, 0.3);
255
+ }
256
+ </style>
257
+ `}
202
258
  `;
203
-
204
259
  const renderMediaQuery = (mediaData) => {
205
260
  // first limit should be '0'
206
261
  return html`
@@ -634,6 +689,166 @@ const scrollBarLightRender = () => {
634
689
  .join('');
635
690
  };
636
691
 
692
+ /**
693
+ * Adjust hex color brightness toward white/black ("mix") or by modifying HSL lightness ("hsl").
694
+ *
695
+ * @param {string} hex - Color as '#rrggbb', 'rrggbb', '#rgb', or 'rgb'.
696
+ * @param {number} factor - -1..1 or -100..100 (percent). Positive = lighten, negative = darken.
697
+ * @param {{mode?: 'mix'|'hsl'}} [options]
698
+ * @returns {string} - Adjusted color as '#rrggbb' (lowercase).
699
+ */
700
+ function adjustHex(hex, factor = 0.1, options = {}) {
701
+ if (typeof hex !== 'string') throw new TypeError('hex must be a string');
702
+ if (typeof factor !== 'number') throw new TypeError('factor must be a number');
703
+
704
+ // normalize factor: allow -100..100 or -1..1
705
+ if (factor > 1 && factor <= 100) factor = factor / 100;
706
+ if (factor < -1 && factor >= -100) factor = factor / 100;
707
+ factor = Math.max(-1, Math.min(1, factor));
708
+
709
+ const mode = options.mode === 'hsl' ? 'hsl' : 'mix';
710
+
711
+ // normalize hex
712
+ let h = hex.replace(/^#/, '').trim();
713
+ if (!(h.length === 3 || h.length === 6)) throw new Error('Invalid hex format');
714
+ if (h.length === 3)
715
+ h = h
716
+ .split('')
717
+ .map((c) => c + c)
718
+ .join('');
719
+
720
+ const r = parseInt(h.slice(0, 2), 16);
721
+ const g = parseInt(h.slice(2, 4), 16);
722
+ const b = parseInt(h.slice(4, 6), 16);
723
+
724
+ const clamp = (v, a = 0, z = 255) => Math.max(a, Math.min(z, v));
725
+
726
+ const rgbToHex = (rr, gg, bb) =>
727
+ '#' +
728
+ [rr, gg, bb]
729
+ .map((v) => Math.round(v).toString(16).padStart(2, '0'))
730
+ .join('')
731
+ .toLowerCase();
732
+
733
+ if (mode === 'mix') {
734
+ // positive: mix toward white (255); negative: mix toward black (0)
735
+ const mixChannel = (c) => {
736
+ if (factor >= 0) {
737
+ return clamp(Math.round(c + (255 - c) * factor));
738
+ } else {
739
+ const a = Math.abs(factor);
740
+ return clamp(Math.round(c * (1 - a)));
741
+ }
742
+ };
743
+ return rgbToHex(mixChannel(r), mixChannel(g), mixChannel(b));
744
+ } else {
745
+ // HSL mode: convert rgb to hsl, adjust L by factor, convert back
746
+ const rgbToHsl = (r, g, b) => {
747
+ r /= 255;
748
+ g /= 255;
749
+ b /= 255;
750
+ const max = Math.max(r, g, b),
751
+ min = Math.min(r, g, b);
752
+ let h = 0,
753
+ s = 0,
754
+ l = (max + min) / 2;
755
+ if (max !== min) {
756
+ const d = max - min;
757
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
758
+ switch (max) {
759
+ case r:
760
+ h = (g - b) / d + (g < b ? 6 : 0);
761
+ break;
762
+ case g:
763
+ h = (b - r) / d + 2;
764
+ break;
765
+ case b:
766
+ h = (r - g) / d + 4;
767
+ break;
768
+ }
769
+ h /= 6;
770
+ }
771
+ return { h, s, l };
772
+ };
773
+
774
+ const hslToRgb = (h, s, l) => {
775
+ let r, g, b;
776
+ if (s === 0) {
777
+ r = g = b = l;
778
+ } else {
779
+ const hue2rgb = (p, q, t) => {
780
+ if (t < 0) t += 1;
781
+ if (t > 1) t -= 1;
782
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
783
+ if (t < 1 / 2) return q;
784
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
785
+ return p;
786
+ };
787
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
788
+ const p = 2 * l - q;
789
+ r = hue2rgb(p, q, h + 1 / 3);
790
+ g = hue2rgb(p, q, h);
791
+ b = hue2rgb(p, q, h - 1 / 3);
792
+ }
793
+ return { r: r * 255, g: g * 255, b: b * 255 };
794
+ };
795
+
796
+ const { h: hh, s: ss, l: ll } = rgbToHsl(r, g, b);
797
+ // add factor to lightness (factor already normalized -1..1)
798
+ let newL = ll + factor;
799
+ newL = Math.max(0, Math.min(1, newL));
800
+ const { r: r2, g: g2, b: b2 } = hslToRgb(hh, ss, newL);
801
+ return rgbToHex(r2, g2, b2);
802
+ }
803
+ }
804
+
805
+ // Convenience helpers:
806
+ function lightenHex(hex, percentOr01 = 0.1, options = {}) {
807
+ return adjustHex(hex, Math.abs(percentOr01), options);
808
+ }
809
+ function darkenHex(hex, percentOr01 = 0.1, options = {}) {
810
+ return adjustHex(hex, -Math.abs(percentOr01), options);
811
+ }
812
+
813
+ const subThemeManager = {
814
+ render: async function () {
815
+ if (darkTheme && this.renderDark) {
816
+ return await this.renderDark();
817
+ } else if (!darkTheme && this.renderLight) {
818
+ return await this.renderLight();
819
+ }
820
+ return html``;
821
+ },
822
+ lightColor: null,
823
+ setLightTheme: function (color) {
824
+ this.lightColor = color;
825
+ this.renderLight = async function () {
826
+ return html`<style>
827
+ button:hover,
828
+ .a-btn:hover,
829
+ .main-btn-menu-active {
830
+ color: ${this.lightColor};
831
+ background-color: ${lightenHex(this.lightColor, 0.8)};
832
+ }
833
+ </style>`;
834
+ };
835
+ },
836
+ darkColor: null,
837
+ setDarkTheme: function (color) {
838
+ this.darkColor = color;
839
+ this.renderDark = async function () {
840
+ return html`<style>
841
+ button:hover,
842
+ .a-btn:hover,
843
+ .main-btn-menu-active {
844
+ color: ${lightenHex(this.darkColor, 0.8)};
845
+ background-color: ${darkenHex(this.darkColor, 0.75)};
846
+ }
847
+ </style>`;
848
+ };
849
+ },
850
+ };
851
+
637
852
  const scrollBarDarkRender = () => {
638
853
  return cssBrowserCodes
639
854
  .map(
@@ -642,8 +857,8 @@ const scrollBarDarkRender = () => {
642
857
  ::-` +
643
858
  b +
644
859
  `-scrollbar {
645
- width: 5px;
646
- height: 5px;
860
+ width: 8px;
861
+ height: 8px;
647
862
  /* line-height: 1em; */
648
863
  }
649
864
 
@@ -659,7 +874,7 @@ const scrollBarDarkRender = () => {
659
874
  b +
660
875
  `-scrollbar-thumb {
661
876
  background: #74747457;
662
- border-radius: 3px;
877
+ border-radius: 4px;
663
878
  }
664
879
 
665
880
  /* Handle on hover */
@@ -811,6 +1026,27 @@ const imageShimmer = () => html`<div
811
1026
  </div>
812
1027
  </div>`;
813
1028
 
1029
+ const renderChessPattern = (patternSize = 20) =>
1030
+ `background: repeating-conic-gradient(#808080 0 25%, #0000 0 50%) 50% / ${patternSize}px ${patternSize}px`;
1031
+
1032
+ const extractBackgroundImageUrl = (element) => {
1033
+ const style = window.getComputedStyle(element);
1034
+ const imageString = style.backgroundImage;
1035
+ const foundUrlRaw = imageString.match(/^url\(?(.+)\)$/i)[1];
1036
+ if (!foundUrlRaw) return null;
1037
+ const foundUrl = foundUrlRaw.replace(/^['|"| ]*/, '').replace(/['" ]*$/, '');
1038
+ if (!foundUrl) return null;
1039
+ return foundUrl;
1040
+ };
1041
+
1042
+ const simpleIconsRender = (selector) => {
1043
+ sa(selector).forEach((el) => {
1044
+ el.src = `https://cdn.simpleicons.org/coveralls/${rgbToHex(window.getComputedStyle(s('html')).color)}`;
1045
+ });
1046
+ };
1047
+
1048
+ const styleFactory = (payload, plain = '') => `style="${renderCssAttr({ style: payload })} ${plain}"`;
1049
+
814
1050
  export {
815
1051
  Css,
816
1052
  Themes,
@@ -843,4 +1079,12 @@ export {
843
1079
  renderWave,
844
1080
  cssEffect,
845
1081
  imageShimmer,
1082
+ simpleIconsRender,
1083
+ extractBackgroundImageUrl,
1084
+ renderChessPattern,
1085
+ subThemeManager,
1086
+ lightenHex,
1087
+ darkenHex,
1088
+ adjustHex,
1089
+ styleFactory,
846
1090
  };
@@ -17,8 +17,8 @@ const CssCommonCore = async () => {
17
17
  await AgGrid.RenderStyle();
18
18
  return html`<style>
19
19
  .top-bar-app-icon {
20
- width: 35px;
21
- height: 35px;
20
+ width: 40px;
21
+ height: 40px;
22
22
  }
23
23
  .mini-title {
24
24
  font-size: 15px;
@@ -33,7 +33,7 @@ const CssCommonCore = async () => {
33
33
  top: 0;
34
34
  left: 0;
35
35
  transition: 0.3s;
36
- height: 5px;
36
+ height: 10px;
37
37
  width: 100%;
38
38
  z-index: 11;
39
39
  }
@@ -51,7 +51,6 @@ const CssCommonCore = async () => {
51
51
  cursor: grabbing !important;
52
52
  }
53
53
  .btn-label-content {
54
- height: 100%;
55
54
  top: 15px;
56
55
  }
57
56
  .badge {
@@ -122,6 +121,7 @@ const CssCommonCore = async () => {
122
121
  left: 0;
123
122
  width: 100%;
124
123
  z-index: 1;
124
+ transition: 0.3s;
125
125
  }
126
126
  @keyframes ripple {
127
127
  to {
@@ -137,10 +137,6 @@ const CssCommonCore = async () => {
137
137
  .title-view-modal .view-title-icon {
138
138
  font-size: 21px !important;
139
139
  }
140
- .plantuml-svg {
141
- width: 100%;
142
- height: auto;
143
- }
144
140
  .down-arrow-submenu {
145
141
  top: -20px;
146
142
  text-align: right;
@@ -611,6 +607,10 @@ const CssCoreLight = {
611
607
  background: gray;
612
608
  transition: 0.3s;
613
609
  }
610
+ .bar-default-modal-icon {
611
+ width: 15px;
612
+ height: 15px;
613
+ }
614
614
  .slide-menu-top-bar {
615
615
  width: 100%;
616
616
  top: 0;