@ti-engine/web-framework 1.19.0 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/.env +4 -4
  2. package/CHANGELOG.md +384 -353
  3. package/README.md +73 -73
  4. package/bin/build/post-install.js +18 -18
  5. package/bin/localization/web-server-labels.json +27 -27
  6. package/bin/static/.well-known/appspecific/com.chrome.devtools.json +5 -5
  7. package/bin/static/fragments/components/component-notification-bar.html +21 -21
  8. package/bin/static/fragments/components/component-sidebar.html +33 -33
  9. package/bin/static/fragments/components/component-tooltip.html +10 -10
  10. package/bin/static/fragments/components/component-topbar.html +5 -5
  11. package/bin/static/fragments/frame-administration.html +2 -2
  12. package/bin/static/fragments/frame-application.html +18 -18
  13. package/bin/static/fragments/frame-dashboard.html +2 -2
  14. package/bin/static/fragments/frame-login.html +119 -119
  15. package/bin/static/fragments/frame-not-found.html +2 -2
  16. package/bin/static/fragments/frame-profile.html +2 -2
  17. package/bin/static/index.html +22 -22
  18. package/bin/static/scripts/ti-charts.js +1591 -1591
  19. package/bin/static/scripts/ti-framework.css +3194 -3194
  20. package/bin/static/scripts/ti-framework.js +1427 -1427
  21. package/bin/static/scripts/ti-theme-black-glass.css +216 -216
  22. package/bin/static/scripts/ti-theme-daylight.css +87 -87
  23. package/bin/web-app-manager.js +660 -663
  24. package/bin/web-server.js +936 -937
  25. package/bin/web-server.json +48 -48
  26. package/components/admin-config-handlers.js +95 -92
  27. package/components/auth-manager.js +438 -442
  28. package/components/authorization.js +135 -135
  29. package/components/config-change-notifier.js +98 -98
  30. package/components/config-registry.js +257 -260
  31. package/components/config-service.js +363 -360
  32. package/components/config-store.js +244 -246
  33. package/components/definitions.types.js +28 -26
  34. package/components/session-store.js +113 -110
  35. package/components/user.js +134 -132
  36. package/components/web-config-env.js +85 -85
  37. package/components/web-handlers.js +803 -800
  38. package/package.json +139 -67
  39. package/types/bin/web-app-manager.d.ts +194 -0
  40. package/types/bin/web-server.d.ts +373 -0
  41. package/types/components/admin-config-handlers.d.ts +11 -0
  42. package/types/components/auth-manager.d.ts +125 -0
  43. package/types/components/authorization.d.ts +54 -0
  44. package/types/components/config-change-notifier.d.ts +73 -0
  45. package/types/components/config-registry.d.ts +149 -0
  46. package/types/components/config-service.d.ts +218 -0
  47. package/types/components/config-store.d.ts +128 -0
  48. package/types/components/definitions.types.d.ts +31 -0
  49. package/types/components/session-store.d.ts +56 -0
  50. package/types/components/user.d.ts +83 -0
  51. package/types/components/web-config-env.d.ts +17 -0
  52. package/types/components/web-handlers.d.ts +23 -0
package/README.md CHANGED
@@ -1,74 +1,74 @@
1
- # ti-engine web framework
2
-
3
- ![Logo](https://raw.githubusercontent.com/Belleal/ti-engine/master/packages/core/docs/ti-engine-icon.ico)
4
-
5
- Flexible framework for the creation of microservices with node.js.
6
-
7
- ## Information
8
-
9
- This is a customizable web framework based on the **ti-engine** framework. Currently under development.
10
-
11
- ## Environment variables
12
-
13
- The web server configuration (host, port, TLS, cookies, etc.) is normally provided via the service configuration file merged in the `TiWebServer` constructor. The following environment variables can override individual values at runtime — useful for container/12-factor deployments where the same image is configured per environment:
14
-
15
- * `TI_WEB_HOST` overrides the bind address (e.g. `0.0.0.0` in a container). Defaults to the value in the web server config.
16
- * `TI_WEB_PORT` overrides the listen port.
17
- * `TI_WEB_USE_TLS` (`true`/`false`) toggles in-app TLS. Set `false` when a reverse proxy / ingress terminates TLS.
18
- * `TI_WEB_TLS_CERT_PATH` / `TI_WEB_TLS_KEY_PATH` override the TLS certificate/key paths (only used when TLS is enabled).
19
- * `TI_WEB_COOKIE_SECRET` sets the session cookie signing secret. Set a stable, private value for durable sessions and multi-replica deployments (otherwise a random per-process value is used).
20
- * `TI_WEB_AUTH_METHODS` (comma-separated) **replaces** the enabled authentication methods (`auth.enabledMethods`), e.g. `openid-google` or `local,openid-google`.
21
- * `TI_WEB_AUTH_ADMINS` (comma-separated) **replaces** the admin allowlist (`auth.admins`). Entries are matched against the session user's user ID, username or email, so an OpenID deployment lists emails. An explicitly empty value means *no admins*.
22
- * `TI_WEB_TRUSTED_ORIGINS` (comma-separated) **replaces** the trusted request origins (`trustedOrigins`) — needed behind proxies that do not present the real external origin.
23
- * `TI_WEB_STATIC_MAX_AGE` (whole seconds) overrides `staticCache.maxAge`. See [Static asset caching](#static-asset-caching).
24
- * `TI_WEB_STATIC_IMMUTABLE` (`true`/`false`) overrides `staticCache.immutable`.
25
- * `TI_WEB_STATIC_IMMUTABLE_PATHS` (comma-separated) **replaces** `staticCache.immutablePaths`. An explicitly empty value means *no long-lived paths*.
26
-
27
- OpenID Connect providers are configured with their own variables — `TI_AZURE_AUTH_CLIENT_ID` / `TI_AZURE_AUTH_CLIENT_SECRET` / `TI_AZURE_AUTH_CALLBACK_URL` / `TI_AZURE_AUTH_DISCOVERY_URL`, and the `TI_GCLOUD_AUTH_*` equivalents. A callback URL may be given either as the full absolute URL registered with the provider (`https://your-host/login/azure-callback`) or as a path (`/login/azure-callback`): the server always listens on the path, while the `redirect_uri` sent to the provider is the absolute value verbatim if one was configured, and otherwise assembled from the request's forwarded protocol/host.
28
-
29
- ## Static asset caching
30
-
31
- Everything under `/static` is served with a `Cache-Control` policy configured by the `staticCache` block:
32
-
33
- ```json
34
- {
35
- "staticCache": {
36
- "maxAge": 0,
37
- "immutable": false,
38
- "immutablePaths": [ "/fonts/" ]
39
- }
40
- }
41
- ```
42
-
43
- * `maxAge` — the `max-age` in **whole seconds** (not an express-style `"1y"` duration string; one is rejected with a warning rather than reinterpreted as milliseconds). `0`, the default, emits `public, max-age=0, must-revalidate`.
44
- * `immutable` — adds the `immutable` directive. Defaults to `false`, and is **ignored with a warning when `maxAge` is 0**, since a response that is stale on arrival cannot also promise never to change.
45
- * `immutablePaths` — path prefixes under `/static` (matched case-sensitively, on a path-segment boundary) served `public, max-age=31536000, immutable` regardless of the two settings above. Defaults to `[ "/fonts/" ]`. This **replaces** rather than merges, so `[]` means no long-lived paths.
46
-
47
- **The default revalidates, and that is deliberate.** `immutable` tells a browser the bytes behind a URL will never change, and browsers honour it so completely that not even a manual reload revalidates. On a stable filename — which is what the framework's own assets use (`/static/scripts/ti-framework.js`, the theme sheets) — the promise is false, and a deployed CSS or JS fix simply never reaches anyone who has already visited, for up to a year, with no way to tell them otherwise. Revalidating costs a conditional request per asset, answered with a `304` from the `ETag`/`Last-Modified` that `express.static` still attaches — headers, no body.
48
-
49
- **Opt back into `immutable` once your filenames are content-addressed.** If your build emits `app.a1b2c3.css`, or your application appends a content hash to each asset URL, the promise becomes true and there is real value in making it:
50
-
51
- ```json
52
- {
53
- "staticCache": { "maxAge": 31536000, "immutable": true }
54
- }
55
- ```
56
-
57
- Fonts are the default exception because a released `.woff2` is an artifact rather than something edited in place, and its filename already carries the family, weight and style. If that is not how a given deployment manages its fonts, clear the list.
58
-
59
- ## Configure HTTPS for development
60
-
61
- Use the `mkcert` tool to create a certificate for development.
62
-
63
- Step 1: Install the tool:
64
- ```text
65
- choco install mkcert
66
- ```
67
- Step 2: Install certificate authority:
68
- ```text
69
- mkcert -install
70
- ```
71
- Step 3: Generate certificate files for localhost:
72
- ```text
73
- mkcert localhost 127.0.0.1 ::1
1
+ # ti-engine web framework
2
+
3
+ ![Logo](https://raw.githubusercontent.com/Belleal/ti-engine/master/packages/core/docs/ti-engine-icon.ico)
4
+
5
+ Flexible framework for the creation of microservices with node.js.
6
+
7
+ ## Information
8
+
9
+ This is a customizable web framework based on the **ti-engine** framework. Currently under development.
10
+
11
+ ## Environment variables
12
+
13
+ The web server configuration (host, port, TLS, cookies, etc.) is normally provided via the service configuration file merged in the `TiWebServer` constructor. The following environment variables can override individual values at runtime — useful for container/12-factor deployments where the same image is configured per environment:
14
+
15
+ * `TI_WEB_HOST` overrides the bind address (e.g. `0.0.0.0` in a container). Defaults to the value in the web server config.
16
+ * `TI_WEB_PORT` overrides the listen port.
17
+ * `TI_WEB_USE_TLS` (`true`/`false`) toggles in-app TLS. Set `false` when a reverse proxy / ingress terminates TLS.
18
+ * `TI_WEB_TLS_CERT_PATH` / `TI_WEB_TLS_KEY_PATH` override the TLS certificate/key paths (only used when TLS is enabled).
19
+ * `TI_WEB_COOKIE_SECRET` sets the session cookie signing secret. Set a stable, private value for durable sessions and multi-replica deployments (otherwise a random per-process value is used).
20
+ * `TI_WEB_AUTH_METHODS` (comma-separated) **replaces** the enabled authentication methods (`auth.enabledMethods`), e.g. `openid-google` or `local,openid-google`.
21
+ * `TI_WEB_AUTH_ADMINS` (comma-separated) **replaces** the admin allowlist (`auth.admins`). Entries are matched against the session user's user ID, username or email, so an OpenID deployment lists emails. An explicitly empty value means *no admins*.
22
+ * `TI_WEB_TRUSTED_ORIGINS` (comma-separated) **replaces** the trusted request origins (`trustedOrigins`) — needed behind proxies that do not present the real external origin.
23
+ * `TI_WEB_STATIC_MAX_AGE` (whole seconds) overrides `staticCache.maxAge`. See [Static asset caching](#static-asset-caching).
24
+ * `TI_WEB_STATIC_IMMUTABLE` (`true`/`false`) overrides `staticCache.immutable`.
25
+ * `TI_WEB_STATIC_IMMUTABLE_PATHS` (comma-separated) **replaces** `staticCache.immutablePaths`. An explicitly empty value means *no long-lived paths*.
26
+
27
+ OpenID Connect providers are configured with their own variables — `TI_AZURE_AUTH_CLIENT_ID` / `TI_AZURE_AUTH_CLIENT_SECRET` / `TI_AZURE_AUTH_CALLBACK_URL` / `TI_AZURE_AUTH_DISCOVERY_URL`, and the `TI_GCLOUD_AUTH_*` equivalents. A callback URL may be given either as the full absolute URL registered with the provider (`https://your-host/login/azure-callback`) or as a path (`/login/azure-callback`): the server always listens on the path, while the `redirect_uri` sent to the provider is the absolute value verbatim if one was configured, and otherwise assembled from the request's forwarded protocol/host.
28
+
29
+ ## Static asset caching
30
+
31
+ Everything under `/static` is served with a `Cache-Control` policy configured by the `staticCache` block:
32
+
33
+ ```json
34
+ {
35
+ "staticCache": {
36
+ "maxAge": 0,
37
+ "immutable": false,
38
+ "immutablePaths": [ "/fonts/" ]
39
+ }
40
+ }
41
+ ```
42
+
43
+ * `maxAge` — the `max-age` in **whole seconds** (not an express-style `"1y"` duration string; one is rejected with a warning rather than reinterpreted as milliseconds). `0`, the default, emits `public, max-age=0, must-revalidate`.
44
+ * `immutable` — adds the `immutable` directive. Defaults to `false`, and is **ignored with a warning when `maxAge` is 0**, since a response that is stale on arrival cannot also promise never to change.
45
+ * `immutablePaths` — path prefixes under `/static` (matched case-sensitively, on a path-segment boundary) served `public, max-age=31536000, immutable` regardless of the two settings above. Defaults to `[ "/fonts/" ]`. This **replaces** rather than merges, so `[]` means no long-lived paths.
46
+
47
+ **The default revalidates, and that is deliberate.** `immutable` tells a browser the bytes behind a URL will never change, and browsers honour it so completely that not even a manual reload revalidates. On a stable filename — which is what the framework's own assets use (`/static/scripts/ti-framework.js`, the theme sheets) — the promise is false, and a deployed CSS or JS fix simply never reaches anyone who has already visited, for up to a year, with no way to tell them otherwise. Revalidating costs a conditional request per asset, answered with a `304` from the `ETag`/`Last-Modified` that `express.static` still attaches — headers, no body.
48
+
49
+ **Opt back into `immutable` once your filenames are content-addressed.** If your build emits `app.a1b2c3.css`, or your application appends a content hash to each asset URL, the promise becomes true and there is real value in making it:
50
+
51
+ ```json
52
+ {
53
+ "staticCache": { "maxAge": 31536000, "immutable": true }
54
+ }
55
+ ```
56
+
57
+ Fonts are the default exception because a released `.woff2` is an artifact rather than something edited in place, and its filename already carries the family, weight and style. If that is not how a given deployment manages its fonts, clear the list.
58
+
59
+ ## Configure HTTPS for development
60
+
61
+ Use the `mkcert` tool to create a certificate for development.
62
+
63
+ Step 1: Install the tool:
64
+ ```text
65
+ choco install mkcert
66
+ ```
67
+ Step 2: Install certificate authority:
68
+ ```text
69
+ mkcert -install
70
+ ```
71
+ Step 3: Generate certificate files for localhost:
72
+ ```text
73
+ mkcert localhost 127.0.0.1 ::1
74
74
  ```
@@ -1,18 +1,18 @@
1
- const fs = require( "node:fs" );
2
- const path = require( "node:path" );
3
-
4
- function copyLibrary( source, destination ) {
5
- try {
6
- fs.mkdirSync( path.dirname( destination ), { recursive: true } );
7
- fs.copyFileSync( source, destination );
8
- console.log( `Copied ${ source } -> ${ destination }` );
9
- } catch ( error ) {
10
- console.error( `Failed to copy ${ source } -> ${ destination }:`, error.message );
11
- process.exit( 1 );
12
- }
13
- }
14
-
15
- const staticDir = path.join( __dirname, "..", "static", "scripts", "lib" );
16
-
17
- copyLibrary( require.resolve( "htmx.org/dist/htmx.min.js" ), path.join( staticDir, "htmx.min.js" ) );
18
- copyLibrary( require.resolve( "@alpinejs/csp/dist/cdn.min.js" ), path.join( staticDir, "alpinejs-csp.min.js" ) );
1
+ const fs = require( "node:fs" );
2
+ const path = require( "node:path" );
3
+
4
+ function copyLibrary( source, destination ) {
5
+ try {
6
+ fs.mkdirSync( path.dirname( destination ), { recursive: true } );
7
+ fs.copyFileSync( source, destination );
8
+ console.log( `Copied ${ source } -> ${ destination }` );
9
+ } catch ( error ) {
10
+ console.error( `Failed to copy ${ source } -> ${ destination }:`, error.message );
11
+ process.exit( 1 );
12
+ }
13
+ }
14
+
15
+ const staticDir = path.join( __dirname, "..", "static", "scripts", "lib" );
16
+
17
+ copyLibrary( require.resolve( "htmx.org/dist/htmx.min.js" ), path.join( staticDir, "htmx.min.js" ) );
18
+ copyLibrary( require.resolve( "@alpinejs/csp/dist/cdn.min.js" ), path.join( staticDir, "alpinejs-csp.min.js" ) );
@@ -1,28 +1,28 @@
1
- {
2
- "interface": {
3
- "default": {
4
- "login": {
5
- "password": {
6
- "en": "Password",
7
- "bg": "Парола"
8
- },
9
- "sign-in": {
10
- "en": "Sign In",
11
- "bg": "Вход"
12
- },
13
- "sign-in-azure": {
14
- "en": "Sign In - Azure",
15
- "bg": "Вход с Azure"
16
- },
17
- "sign-in-google": {
18
- "en": "Sign In - Google",
19
- "bg": "Вход с Google"
20
- },
21
- "username": {
22
- "en": "Username",
23
- "bg": "Потребител"
24
- }
25
- }
26
- }
27
- }
1
+ {
2
+ "interface": {
3
+ "default": {
4
+ "login": {
5
+ "password": {
6
+ "en": "Password",
7
+ "bg": "Парола"
8
+ },
9
+ "sign-in": {
10
+ "en": "Sign In",
11
+ "bg": "Вход"
12
+ },
13
+ "sign-in-azure": {
14
+ "en": "Sign In - Azure",
15
+ "bg": "Вход с Azure"
16
+ },
17
+ "sign-in-google": {
18
+ "en": "Sign In - Google",
19
+ "bg": "Вход с Google"
20
+ },
21
+ "username": {
22
+ "en": "Username",
23
+ "bg": "Потребител"
24
+ }
25
+ }
26
+ }
27
+ }
28
28
  }
@@ -1,6 +1,6 @@
1
- {
2
- "workspace": {
3
- "root": "packages/web-framework",
4
- "uuid": "a6c9b71a-41c3-448d-a680-7c1f6c5b42b0"
5
- }
1
+ {
2
+ "workspace": {
3
+ "root": "packages/web-framework",
4
+ "uuid": "a6c9b71a-41c3-448d-a680-7c1f6c5b42b0"
5
+ }
6
6
  }
@@ -1,21 +1,21 @@
1
- <div id="ti-notifications" x-data="tiComponentNotificationBar" class="ti-toast-stack" aria-live="polite" aria-atomic="false">
2
- <template x-for="n in notifications" x-bind:key="n.id">
3
- <div class="ti-toast" x-bind:class="n.tone || 'info'" role="alert">
4
- <div class="ti-toast-bar" aria-hidden="true"></div>
5
- <div class="ti-toast-icon" aria-hidden="true">
6
- <span class="ti-icon check md" aria-hidden="true" x-show="n.tone === 'success'"></span>
7
- <span class="ti-icon close md" aria-hidden="true" x-show="n.tone === 'danger'"></span>
8
- <span class="ti-icon warning-triangle md" aria-hidden="true" x-show="n.tone === 'warn'"></span>
9
- <span class="ti-icon info-circle md" aria-hidden="true" x-show="!n.tone || n.tone === 'info'"></span>
10
- </div>
11
- <div class="ti-toast-body">
12
- <div class="ti-toast-title" x-text="n.title || ''"></div>
13
- <div class="ti-toast-msg" x-text="n.message || ''"></div>
14
- <div class="ti-toast-details" x-show="n.details" x-text="n.details || ''"></div>
15
- </div>
16
- <button class="ti-toast-close" @click="remove(n.id)" aria-label="Dismiss notification" type="button">
17
- <span class="ti-icon close sm" aria-hidden="true"></span>
18
- </button>
19
- </div>
20
- </template>
21
- </div>
1
+ <div id="ti-notifications" x-data="tiComponentNotificationBar" class="ti-toast-stack" aria-live="polite" aria-atomic="false">
2
+ <template x-for="n in notifications" x-bind:key="n.id">
3
+ <div class="ti-toast" x-bind:class="n.tone || 'info'" role="alert">
4
+ <div class="ti-toast-bar" aria-hidden="true"></div>
5
+ <div class="ti-toast-icon" aria-hidden="true">
6
+ <span class="ti-icon check md" aria-hidden="true" x-show="n.tone === 'success'"></span>
7
+ <span class="ti-icon close md" aria-hidden="true" x-show="n.tone === 'danger'"></span>
8
+ <span class="ti-icon warning-triangle md" aria-hidden="true" x-show="n.tone === 'warn'"></span>
9
+ <span class="ti-icon info-circle md" aria-hidden="true" x-show="!n.tone || n.tone === 'info'"></span>
10
+ </div>
11
+ <div class="ti-toast-body">
12
+ <div class="ti-toast-title" x-text="n.title || ''"></div>
13
+ <div class="ti-toast-msg" x-text="n.message || ''"></div>
14
+ <div class="ti-toast-details" x-show="n.details" x-text="n.details || ''"></div>
15
+ </div>
16
+ <button class="ti-toast-close" @click="remove(n.id)" aria-label="Dismiss notification" type="button">
17
+ <span class="ti-icon close sm" aria-hidden="true"></span>
18
+ </button>
19
+ </div>
20
+ </template>
21
+ </div>
@@ -1,33 +1,33 @@
1
- <nav class="ti-sidebar" x-data="tiComponentSidebarNav" aria-label="Main navigation">
2
- <button class="ti-sidebar-collapse-btn" @click="toggleCollapse()" x-bind:aria-label="collapsed ? 'Expand sidebar' : 'Collapse sidebar'" type="button">
3
- <span class="ti-icon chevron-left xs" aria-hidden="true"></span>
4
- </button>
5
-
6
- <!-- Brand slot — override in app-specific frame -->
7
- <div class="ti-sidebar-brand">
8
- <div class="ti-sidebar-brand-mark">T</div>
9
- <div class="ti-sidebar-brand-text-block">
10
- <span class="ti-sidebar-brand-text">ti-engine</span>
11
- </div>
12
- </div>
13
-
14
- <!-- Navigation slot — override in app-specific frame -->
15
- <div class="ti-sidebar-nav">
16
- <a href="/" class="ti-sidebar-item" data-tip="Dashboard" aria-label="Dashboard">
17
- <span class="ti-sidebar-item-icon">
18
- <span class="ti-icon dashboard md" aria-hidden="true"></span>
19
- </span>
20
- <span class="ti-sidebar-item-label">Dashboard</span>
21
- </a>
22
- </div>
23
-
24
- <!-- Footer -->
25
- <div class="ti-sidebar-foot">
26
- <button class="ti-sidebar-item" @click="toggleTheme()" data-tip="Toggle theme" aria-label="Toggle theme" type="button">
27
- <span class="ti-sidebar-item-icon">
28
- <span class="ti-icon sun md" aria-hidden="true"></span>
29
- </span>
30
- <span class="ti-sidebar-item-label" x-text="theme === 'daylight' ? 'Glass Theme' : 'Daylight Theme'">Toggle Theme</span>
31
- </button>
32
- </div>
33
- </nav>
1
+ <nav class="ti-sidebar" x-data="tiComponentSidebarNav" aria-label="Main navigation">
2
+ <button class="ti-sidebar-collapse-btn" @click="toggleCollapse()" x-bind:aria-label="collapsed ? 'Expand sidebar' : 'Collapse sidebar'" type="button">
3
+ <span class="ti-icon chevron-left xs" aria-hidden="true"></span>
4
+ </button>
5
+
6
+ <!-- Brand slot — override in app-specific frame -->
7
+ <div class="ti-sidebar-brand">
8
+ <div class="ti-sidebar-brand-mark">T</div>
9
+ <div class="ti-sidebar-brand-text-block">
10
+ <span class="ti-sidebar-brand-text">ti-engine</span>
11
+ </div>
12
+ </div>
13
+
14
+ <!-- Navigation slot — override in app-specific frame -->
15
+ <div class="ti-sidebar-nav">
16
+ <a href="/" class="ti-sidebar-item" data-tip="Dashboard" aria-label="Dashboard">
17
+ <span class="ti-sidebar-item-icon">
18
+ <span class="ti-icon dashboard md" aria-hidden="true"></span>
19
+ </span>
20
+ <span class="ti-sidebar-item-label">Dashboard</span>
21
+ </a>
22
+ </div>
23
+
24
+ <!-- Footer -->
25
+ <div class="ti-sidebar-foot">
26
+ <button class="ti-sidebar-item" @click="toggleTheme()" data-tip="Toggle theme" aria-label="Toggle theme" type="button">
27
+ <span class="ti-sidebar-item-icon">
28
+ <span class="ti-icon sun md" aria-hidden="true"></span>
29
+ </span>
30
+ <span class="ti-sidebar-item-label" x-text="theme === 'daylight' ? 'Glass Theme' : 'Daylight Theme'">Toggle Theme</span>
31
+ </button>
32
+ </div>
33
+ </nav>
@@ -1,11 +1,11 @@
1
- <div x-data="tiComponentTooltip()"
2
- x-on:mouseover="handleEnter($event)"
3
- x-on:mouseout="handleLeave($event)"
4
- x-on:focusin="handleEnter($event)"
5
- x-on:focusout="handleLeave($event)"
6
- class="ti-tooltip">
7
- <div x-show="isVisible"
8
- x-text="text"
9
- x-transition
10
- class="ti-tooltip-bubble"></div>
1
+ <div x-data="tiComponentTooltip()"
2
+ x-on:mouseover="handleEnter($event)"
3
+ x-on:mouseout="handleLeave($event)"
4
+ x-on:focusin="handleEnter($event)"
5
+ x-on:focusout="handleLeave($event)"
6
+ class="ti-tooltip">
7
+ <div x-show="isVisible"
8
+ x-text="text"
9
+ x-transition
10
+ class="ti-tooltip-bubble"></div>
11
11
  </div>
@@ -1,6 +1,6 @@
1
- <header id="ti-topbar" class="ti-topbar" x-data="tiComponentTopbar">
2
- <div id="ti-topbar-info">
3
- <div class="ti-topbar-title" x-text="screenTitle"></div>
4
- <div class="ti-topbar-sub" x-show="$store.tiApplication.topbarSubtitle" x-text="$store.tiApplication.topbarSubtitle"></div>
5
- </div>
1
+ <header id="ti-topbar" class="ti-topbar" x-data="tiComponentTopbar">
2
+ <div id="ti-topbar-info">
3
+ <div class="ti-topbar-title" x-text="screenTitle"></div>
4
+ <div class="ti-topbar-sub" x-show="$store.tiApplication.topbarSubtitle" x-text="$store.tiApplication.topbarSubtitle"></div>
5
+ </div>
6
6
  </header>
@@ -1,3 +1,3 @@
1
- <div>
2
- <span>Administration</span>
1
+ <div>
2
+ <span>Administration</span>
3
3
  </div>
@@ -1,19 +1,19 @@
1
- <div class="ti-application" x-data="tiApplication" x-bind:class="{ collapsed: collapsed }">
2
- <!-- Sidebar -->
3
- <ti-component-sidebar-placeholder></ti-component-sidebar-placeholder>
4
-
5
- <!-- Content -->
6
- <div id="ti-content-wrapper" class="ti-content">
7
- <!-- Topbar -->
8
- <ti-component-topbar-placeholder></ti-component-topbar-placeholder>
9
-
10
- <!-- Application Screen -->
11
- <div id="ti-content" class="ti-page-scrollable">
12
- <ti-nested-frame-placeholder hx-get="/app/dashboard" hx-trigger="load" hx-target="this" hx-swap="outerHTML"
13
- hx-push-url="true"></ti-nested-frame-placeholder>
14
- </div>
15
- </div>
16
-
17
- <!-- Toast notification stack -->
18
- <ti-component-notification-bar-placeholder></ti-component-notification-bar-placeholder>
1
+ <div class="ti-application" x-data="tiApplication" x-bind:class="{ collapsed: collapsed }">
2
+ <!-- Sidebar -->
3
+ <ti-component-sidebar-placeholder></ti-component-sidebar-placeholder>
4
+
5
+ <!-- Content -->
6
+ <div id="ti-content-wrapper" class="ti-content">
7
+ <!-- Topbar -->
8
+ <ti-component-topbar-placeholder></ti-component-topbar-placeholder>
9
+
10
+ <!-- Application Screen -->
11
+ <div id="ti-content" class="ti-page-scrollable">
12
+ <ti-nested-frame-placeholder hx-get="/app/dashboard" hx-trigger="load" hx-target="this" hx-swap="outerHTML"
13
+ hx-push-url="true"></ti-nested-frame-placeholder>
14
+ </div>
15
+ </div>
16
+
17
+ <!-- Toast notification stack -->
18
+ <ti-component-notification-bar-placeholder></ti-component-notification-bar-placeholder>
19
19
  </div>
@@ -1,3 +1,3 @@
1
- <div>
2
- <span>Dashboard</span>
1
+ <div>
2
+ <span>Dashboard</span>
3
3
  </div>