@record-evolution/widget-sidenav 1.0.13 → 1.0.15

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.
@@ -1,15 +1,15 @@
1
- import { css as d, LitElement as u, html as p } from "lit";
2
- import { property as h, state as c, customElement as g } from "lit/decorators.js";
3
- import { repeat as m } from "lit/directives/repeat.js";
1
+ import { css as u, LitElement as d, html as p } from "lit";
2
+ import { property as h, state as c, customElement as m } from "lit/decorators.js";
3
+ import { repeat as g } from "lit/directives/repeat.js";
4
4
  import "@material/web/icon/icon.js";
5
- var f = Object.defineProperty, y = Object.getOwnPropertyDescriptor, a = (t, e, o, i) => {
6
- for (var r = i > 1 ? void 0 : i ? y(e, o) : e, n = t.length - 1, l; n >= 0; n--)
7
- (l = t[n]) && (r = (i ? l(e, o, r) : l(r)) || r);
8
- return i && r && f(e, o, r), r;
5
+ var f = Object.defineProperty, v = Object.getOwnPropertyDescriptor, n = (t, e, i, o) => {
6
+ for (var r = o > 1 ? void 0 : o ? v(e, i) : e, l = t.length - 1, a; l >= 0; l--)
7
+ (a = t[l]) && (r = (o ? a(e, i, r) : a(r)) || r);
8
+ return o && r && f(e, i, r), r;
9
9
  };
10
- let s = class extends u {
10
+ let s = class extends d {
11
11
  constructor() {
12
- super(...arguments), this.version = "1.0.13";
12
+ super(...arguments), this.version = "1.0.15";
13
13
  }
14
14
  update(t) {
15
15
  t.has("theme") && this.registerTheme(this.theme), super.update(t);
@@ -18,8 +18,8 @@ let s = class extends u {
18
18
  this.registerTheme(this.theme);
19
19
  }
20
20
  registerTheme(t) {
21
- const e = getComputedStyle(this).getPropertyValue("--re-text-color").trim(), o = getComputedStyle(this).getPropertyValue("--re-tile-background-color").trim();
22
- this.themeBgColor = o || this.theme?.theme_object?.backgroundColor, this.themeTitleColor = e || this.theme?.theme_object?.title?.textStyle?.color;
21
+ const e = getComputedStyle(this).getPropertyValue("--re-text-color").trim(), i = getComputedStyle(this).getPropertyValue("--re-tile-background-color").trim();
22
+ this.themeBgColor = i || this.theme?.theme_object?.backgroundColor, this.themeTitleColor = e || this.theme?.theme_object?.title?.textStyle?.color;
23
23
  }
24
24
  handleNavItemClick(t) {
25
25
  const e = new CustomEvent("nav-submit", {
@@ -32,17 +32,27 @@ let s = class extends u {
32
32
  trimRoute(t) {
33
33
  return t = String(t), t ? "/" + t.split("/").filter(Boolean).join("/") : "";
34
34
  }
35
- addSlashes(t) {
36
- return t.route = String(t.route), !t.route?.endsWith("/") && t.trailingSlash && (t.route += "/"), !t.route?.startsWith("/") && t.leadingSlash && (t.route = "/" + t.route), t.route;
35
+ resolveRoute(t) {
36
+ let e = String(t?.route ?? "");
37
+ if (t?.variables)
38
+ for (const i of t.variables)
39
+ i.label && (e = e.split(`{{${i.label}}}`).join(encodeURIComponent(String(i.value ?? ""))));
40
+ if (e.includes("*")) {
41
+ const i = (this.route || "").split("/").filter(Boolean), o = e.split("/").filter(Boolean);
42
+ for (let r = 0; r < o.length; r++)
43
+ o[r] === "*" && (o[r] = i[r] ?? "");
44
+ e = (e.startsWith("/") ? "/" : "") + o.filter(Boolean).join("/");
45
+ }
46
+ return e;
37
47
  }
38
48
  matchesRoute(t) {
39
49
  if (t === void 0) return !1;
40
50
  t = String(t);
41
- const e = this.trimRoute(decodeURIComponent(this.route || "/")), o = this.trimRoute(t);
42
- return t.startsWith("/") ? e.startsWith(o) : e.endsWith(o) || e === o;
51
+ const e = this.trimRoute(decodeURIComponent(this.route || "/")), i = this.trimRoute(t);
52
+ return t.startsWith("/") ? e.startsWith(i) : e.endsWith(i) || e === i;
43
53
  }
44
54
  render() {
45
- const t = this.inputData?.style?.fontSize ?? 16, e = (this.inputData?.style?.fontSize ?? 16) * 1.5, o = t * 0.4;
55
+ const t = this.inputData?.style?.fontSize ?? 16, e = (this.inputData?.style?.fontSize ?? 16) * 1.5, i = t * 0.4;
46
56
  return p`
47
57
  <div
48
58
  class="wrapper"
@@ -54,27 +64,32 @@ let s = class extends u {
54
64
  class="paging"
55
65
  style=${this.inputData?.route ? "cursor: pointer" : ""}
56
66
  ?active=${this.inputData?.title}
57
- @click=${() => this.handleNavItemClick(this.addSlashes(this.inputData))}
67
+ @click=${() => this.handleNavItemClick(
68
+ this.resolveRoute({
69
+ route: this.inputData?.route,
70
+ variables: this.inputData?.variables
71
+ })
72
+ )}
58
73
  >
59
74
  ${this.inputData?.title}
60
75
  </h2>
61
76
  <div class="nav-list">
62
- ${m(
77
+ ${g(
63
78
  this.inputData?.navItems || [],
64
- (i) => i.label,
65
- (i) => p`
79
+ (o) => o.label,
80
+ (o) => p`
66
81
  <div
67
- class="nav-item ${this.matchesRoute(this.addSlashes(i)) ? "selected" : ""}"
68
- style="gap: ${o}px;"
69
- @click=${() => this.handleNavItemClick(this.addSlashes(i))}
82
+ class="nav-item ${this.matchesRoute(this.resolveRoute(o)) ? "selected" : ""}"
83
+ style="gap: ${i}px;"
84
+ @click=${() => this.handleNavItemClick(this.resolveRoute(o))}
70
85
  >
71
- ${i.iconName ? p`
86
+ ${o.iconName ? p`
72
87
  <md-icon
73
88
  style="font-size: ${e}px;width: ${e}px;"
74
- >${i.iconName}
89
+ >${o.iconName}
75
90
  </md-icon>
76
91
  ` : ""}
77
- ${i.label}
92
+ ${o.label}
78
93
  </div>
79
94
  `
80
95
  )}
@@ -83,7 +98,7 @@ let s = class extends u {
83
98
  `;
84
99
  }
85
100
  };
86
- s.styles = d`
101
+ s.styles = u`
87
102
  :host {
88
103
  display: block;
89
104
  font-family: sans-serif;
@@ -136,23 +151,23 @@ s.styles = d`
136
151
  font-size: 1.2em;
137
152
  }
138
153
  `;
139
- a([
154
+ n([
140
155
  h({ type: Object })
141
156
  ], s.prototype, "inputData", 2);
142
- a([
157
+ n([
143
158
  h({ type: Object })
144
159
  ], s.prototype, "theme", 2);
145
- a([
160
+ n([
146
161
  h({ type: String })
147
162
  ], s.prototype, "route", 2);
148
- a([
163
+ n([
149
164
  c()
150
165
  ], s.prototype, "themeBgColor", 2);
151
- a([
166
+ n([
152
167
  c()
153
168
  ], s.prototype, "themeTitleColor", 2);
154
- s = a([
155
- g("widget-sidenav-1.0.13")
169
+ s = n([
170
+ m("widget-sidenav-1.0.15")
156
171
  ], s);
157
172
  export {
158
173
  s as WidgetSidenav
@@ -1 +1 @@
1
- {"version":3,"file":"widget-sidenav.js","sources":["../src/widget-sidenav.ts"],"sourcesContent":["import { html, css, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { repeat } from 'lit/directives/repeat.js'\nimport { InputData } from './definition-schema'\n\nimport '@material/web/icon/icon.js'\n\ntype Theme = {\n theme_name: string\n theme_object: any\n}\n@customElement('widget-sidenav-versionplaceholder')\nexport class WidgetSidenav extends LitElement {\n @property({ type: Object }) inputData?: InputData\n @property({ type: Object }) theme?: Theme\n @property({ type: String }) route?: string\n\n @state() private themeBgColor?: string\n @state() private themeTitleColor?: string\n\n version: string = 'versionplaceholder'\n\n update(changedProperties: Map<string, any>) {\n if (changedProperties.has('theme')) {\n this.registerTheme(this.theme)\n }\n\n super.update(changedProperties)\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n this.registerTheme(this.theme)\n }\n\n registerTheme(theme?: Theme) {\n const cssTextColor = getComputedStyle(this).getPropertyValue('--re-text-color').trim()\n const cssBgColor = getComputedStyle(this).getPropertyValue('--re-tile-background-color').trim()\n this.themeBgColor = cssBgColor || this.theme?.theme_object?.backgroundColor\n this.themeTitleColor = cssTextColor || this.theme?.theme_object?.title?.textStyle?.color\n }\n\n handleNavItemClick(route?: string) {\n // console.log('Navigating to:', item.route)\n const event = new CustomEvent('nav-submit', {\n detail: { path: String(route) },\n bubbles: true,\n composed: true\n })\n this.dispatchEvent(event)\n }\n\n trimRoute(route?: string) {\n route = String(route)\n if (!route) return ''\n return '/' + route.split('/').filter(Boolean).join('/')\n }\n\n addSlashes(item?: any): string | undefined {\n item.route = String(item.route)\n if (!item.route?.endsWith('/') && item.trailingSlash) {\n item.route += '/'\n }\n if (!item.route?.startsWith('/') && item.leadingSlash) {\n item.route = '/' + item.route\n }\n return item.route\n }\n\n matchesRoute(itemRoute?: string) {\n if (itemRoute === undefined) return false\n itemRoute = String(itemRoute)\n const route = this.trimRoute(decodeURIComponent(this.route || '/'))\n const subRoute = this.trimRoute(itemRoute)\n if (itemRoute.startsWith('/')) {\n return route.startsWith(subRoute)\n } else {\n return route.endsWith(subRoute) || route === subRoute\n }\n }\n\n static styles = css`\n :host {\n display: block;\n font-family: sans-serif;\n box-sizing: border-box;\n margin: auto;\n }\n\n .paging:not([active]) {\n display: none !important;\n }\n\n .wrapper {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n padding: 12px;\n box-sizing: border-box;\n }\n\n .nav-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: 12px;\n overflow-y: auto;\n flex-grow: 1;\n }\n\n .nav-item {\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px;\n border-radius: 4px;\n }\n\n md-icon {\n font-family: 'Material Symbols Outlined';\n }\n\n .selected {\n background-color: rgba(0, 0, 0, 0.1);\n }\n\n h2 {\n margin: 0;\n padding: 0px;\n font-size: 1.2em;\n }\n `\n\n render() {\n const fontSize = this.inputData?.style?.fontSize ?? 16\n const iconFontSize = (this.inputData?.style?.fontSize ?? 16) * 1.5\n const gap = fontSize * 0.4\n return html`\n <div\n class=\"wrapper\"\n style=\"background-color: ${this.inputData?.style?.backgroundColor ||\n this.themeBgColor}; color: ${this.inputData?.style?.color || this.themeTitleColor};\n font-weight: ${this.inputData?.style?.fontWeight};\n font-size: ${fontSize}px;\"\n >\n <h2\n class=\"paging\"\n style=${this.inputData?.route ? 'cursor: pointer' : ''}\n ?active=${this.inputData?.title}\n @click=${() => this.handleNavItemClick(this.addSlashes(this.inputData))}\n >\n ${this.inputData?.title}\n </h2>\n <div class=\"nav-list\">\n ${repeat(\n this.inputData?.navItems || [],\n (item) => item.label,\n (item) => html`\n <div\n class=\"nav-item ${this.matchesRoute(this.addSlashes(item)) ? 'selected' : ''}\"\n style=\"gap: ${gap}px;\"\n @click=${() => this.handleNavItemClick(this.addSlashes(item))}\n >\n ${item.iconName\n ? html`\n <md-icon\n style=\"font-size: ${iconFontSize}px;width: ${iconFontSize}px;\"\n >${item.iconName}\n </md-icon>\n `\n : ''}\n ${item.label}\n </div>\n `\n )}\n </div>\n </div>\n `\n }\n}\n"],"names":["WidgetSidenav","LitElement","changedProperties","_changedProperties","theme","cssTextColor","cssBgColor","route","event","item","itemRoute","subRoute","fontSize","iconFontSize","gap","html","repeat","css","__decorateClass","property","state","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"widget-sidenav.js","sources":["../src/widget-sidenav.ts"],"sourcesContent":["import { html, css, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { repeat } from 'lit/directives/repeat.js'\nimport { InputData } from './definition-schema'\n\nimport '@material/web/icon/icon.js'\n\ntype Theme = {\n theme_name: string\n theme_object: any\n}\n@customElement('widget-sidenav-versionplaceholder')\nexport class WidgetSidenav extends LitElement {\n @property({ type: Object }) inputData?: InputData\n @property({ type: Object }) theme?: Theme\n @property({ type: String }) route?: string\n\n @state() private themeBgColor?: string\n @state() private themeTitleColor?: string\n\n version: string = 'versionplaceholder'\n\n update(changedProperties: Map<string, any>) {\n if (changedProperties.has('theme')) {\n this.registerTheme(this.theme)\n }\n\n super.update(changedProperties)\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n this.registerTheme(this.theme)\n }\n\n registerTheme(theme?: Theme) {\n const cssTextColor = getComputedStyle(this).getPropertyValue('--re-text-color').trim()\n const cssBgColor = getComputedStyle(this).getPropertyValue('--re-tile-background-color').trim()\n this.themeBgColor = cssBgColor || this.theme?.theme_object?.backgroundColor\n this.themeTitleColor = cssTextColor || this.theme?.theme_object?.title?.textStyle?.color\n }\n\n handleNavItemClick(route?: string) {\n // console.log('Navigating to:', item.route)\n const event = new CustomEvent('nav-submit', {\n detail: { path: String(route) },\n bubbles: true,\n composed: true\n })\n this.dispatchEvent(event)\n }\n\n trimRoute(route?: string) {\n route = String(route)\n if (!route) return ''\n return '/' + route.split('/').filter(Boolean).join('/')\n }\n\n resolveRoute(item?: any): string | undefined {\n let route = String(item?.route ?? '')\n if (item?.variables) {\n for (const variable of item.variables) {\n if (variable.label) {\n route = route\n .split(`{{${variable.label}}}`)\n .join(encodeURIComponent(String(variable.value ?? '')))\n }\n }\n }\n if (route.includes('*')) {\n const currentSegments = (this.route || '').split('/').filter(Boolean)\n const routeSegments = route.split('/').filter(Boolean)\n for (let i = 0; i < routeSegments.length; i++) {\n if (routeSegments[i] === '*') {\n routeSegments[i] = currentSegments[i] ?? ''\n }\n }\n route = (route.startsWith('/') ? '/' : '') + routeSegments.filter(Boolean).join('/')\n }\n return route\n }\n\n matchesRoute(itemRoute?: string) {\n if (itemRoute === undefined) return false\n itemRoute = String(itemRoute)\n const route = this.trimRoute(decodeURIComponent(this.route || '/'))\n const subRoute = this.trimRoute(itemRoute)\n if (itemRoute.startsWith('/')) {\n return route.startsWith(subRoute)\n } else {\n return route.endsWith(subRoute) || route === subRoute\n }\n }\n\n static styles = css`\n :host {\n display: block;\n font-family: sans-serif;\n box-sizing: border-box;\n margin: auto;\n }\n\n .paging:not([active]) {\n display: none !important;\n }\n\n .wrapper {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n padding: 12px;\n box-sizing: border-box;\n }\n\n .nav-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: 12px;\n overflow-y: auto;\n flex-grow: 1;\n }\n\n .nav-item {\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px;\n border-radius: 4px;\n }\n\n md-icon {\n font-family: 'Material Symbols Outlined';\n }\n\n .selected {\n background-color: rgba(0, 0, 0, 0.1);\n }\n\n h2 {\n margin: 0;\n padding: 0px;\n font-size: 1.2em;\n }\n `\n\n render() {\n const fontSize = this.inputData?.style?.fontSize ?? 16\n const iconFontSize = (this.inputData?.style?.fontSize ?? 16) * 1.5\n const gap = fontSize * 0.4\n return html`\n <div\n class=\"wrapper\"\n style=\"background-color: ${this.inputData?.style?.backgroundColor ||\n this.themeBgColor}; color: ${this.inputData?.style?.color || this.themeTitleColor};\n font-weight: ${this.inputData?.style?.fontWeight};\n font-size: ${fontSize}px;\"\n >\n <h2\n class=\"paging\"\n style=${this.inputData?.route ? 'cursor: pointer' : ''}\n ?active=${this.inputData?.title}\n @click=${() =>\n this.handleNavItemClick(\n this.resolveRoute({\n route: this.inputData?.route,\n variables: this.inputData?.variables\n })\n )}\n >\n ${this.inputData?.title}\n </h2>\n <div class=\"nav-list\">\n ${repeat(\n this.inputData?.navItems || [],\n (item) => item.label,\n (item) => html`\n <div\n class=\"nav-item ${this.matchesRoute(this.resolveRoute(item))\n ? 'selected'\n : ''}\"\n style=\"gap: ${gap}px;\"\n @click=${() => this.handleNavItemClick(this.resolveRoute(item))}\n >\n ${item.iconName\n ? html`\n <md-icon\n style=\"font-size: ${iconFontSize}px;width: ${iconFontSize}px;\"\n >${item.iconName}\n </md-icon>\n `\n : ''}\n ${item.label}\n </div>\n `\n )}\n </div>\n </div>\n `\n }\n}\n"],"names":["WidgetSidenav","LitElement","changedProperties","_changedProperties","theme","cssTextColor","cssBgColor","route","event","item","variable","currentSegments","routeSegments","i","itemRoute","subRoute","fontSize","iconFontSize","gap","html","repeat","css","__decorateClass","property","state","customElement"],"mappings":"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"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Webcomponent widget-sidenav following open-wc recommendations",
4
4
  "license": "MIT",
5
5
  "author": "widget-sidenav",
6
- "version": "1.0.13",
6
+ "version": "1.0.15",
7
7
  "engines": {
8
8
  "node": ">=24.9.0",
9
9
  "npm": ">=10.0.2"
@@ -14,11 +14,12 @@
14
14
  "files": [
15
15
  "dist",
16
16
  "src",
17
- "thumbnail.png"
17
+ "thumbnail.png",
18
+ "thumbnail.webp"
18
19
  ],
19
20
  "scripts": {
20
21
  "analyze": "cem analyze --litelement",
21
- "start": "vite",
22
+ "start": "vite build --watch & vite",
22
23
  "build": "vite build",
23
24
  "watch": "vite build --watch",
24
25
  "link": "npm run build && npm link && cd ../RESWARM/frontend && npm link @record-evolution/widget-sidenav",
@@ -14,13 +14,21 @@ export type TitleSettings = string;
14
14
  */
15
15
  export type TitleNavigation = string;
16
16
  /**
17
- * When enabled, prepends '/' to the title's navigation route making it absolute from the root. When disabled, routes are relative to the current location.
17
+ * The variable name used in the route string. Reference this in your route using the {{label}} syntax. Use descriptive names like 'temperature', 'status', 'deviceName'.
18
18
  */
19
- export type AddLeadingSlash = boolean;
19
+ export type Label = string;
20
+ /**
21
+ * The replacement text that will appear in place of {{label}} in the rendered output. Can be a static value or bound to a data column for dynamic updates.
22
+ */
23
+ export type Value = string;
20
24
  /**
21
- * When enabled, appends '/' to the end of the title's navigation route. Required by some routing configurations.
25
+ * Array of variable definitions for dynamic route segment substitution. Each variable has a label (used in the route string as {{label}}) and a value (the replacement text). Values can be static or bound to data columns for real-time updates.
22
26
  */
23
- export type AddTraillingSlash = boolean;
27
+ export type TitleNavigationVariables = {
28
+ label?: Label;
29
+ value?: Value;
30
+ [k: string]: unknown;
31
+ }[];
24
32
  /**
25
33
  * Font size in pixels for navigation item labels.
26
34
  */
@@ -32,32 +40,39 @@ export type FontWeight = number;
32
40
  /**
33
41
  * The text displayed for this navigation item. Should clearly describe the destination section.
34
42
  */
35
- export type Label = string;
43
+ export type Label1 = string;
36
44
  /**
37
45
  * Material icon name displayed alongside the label. Find icon names at https://fonts.google.com/icons (e.g., 'dashboard', 'settings', 'analytics', 'people').
38
46
  */
39
47
  export type IconName = string;
40
48
  /**
41
- * The destination path when this item is clicked. Use relative paths that append to the current URL, or enable leadingSlash for absolute routing.
49
+ * The destination path when this item is clicked. Supports two dynamic substitution mechanisms: (1) Variable placeholders using double curly braces — define variables in the 'Variables' array below and reference them as {{variableName}} in the route string (e.g., '/device/{{deviceId}}/details' where a variable with label 'deviceId' provides the value). (2) Wildcard segments using a single asterisk '*' as a full path segment — each '*' is replaced at runtime by the segment at the same position from the current browser route (e.g., '/* /settings' navigates to the settings page while preserving the first segment of the current URL). The '*' must be the entire segment to be substituted; partial wildcards like 'test*' are treated as literal text. Routes starting with '/' are absolute; routes without a leading slash are relative to the current location.
42
50
  */
43
51
  export type NavigationRoute = string;
44
52
  /**
45
- * When enabled, prepends '/' to this item's route making it absolute from the root.
53
+ * The variable name used in the route string. Reference this in your route using the {{label}} syntax. Use descriptive names like 'temperature', 'status', 'deviceName'.
54
+ */
55
+ export type Label2 = string;
56
+ /**
57
+ * The replacement text that will appear in place of {{label}} in the rendered output. Can be a static value or bound to a data column for dynamic updates.
46
58
  */
47
- export type AddLeadingSlash1 = boolean;
59
+ export type Value1 = string;
48
60
  /**
49
- * When enabled, appends '/' to the end of this item's route.
61
+ * Array of variable definitions for dynamic route segment substitution. Each variable has a label (used in the route string as {{label}}) and a value (the replacement text). Values can be static or bound to data columns for real-time updates.
50
62
  */
51
- export type AddTraillingSlash1 = boolean;
63
+ export type NavigationVariables = {
64
+ label?: Label2;
65
+ value?: Value1;
66
+ [k: string]: unknown;
67
+ }[];
52
68
  /**
53
69
  * Array of navigation links displayed vertically in the sidebar. Each item can have a label, icon, and destination route.
54
70
  */
55
71
  export type NavigationItems = {
56
- label?: Label;
72
+ label?: Label1;
57
73
  iconName?: IconName;
58
74
  route?: NavigationRoute;
59
- leadingSlash?: AddLeadingSlash1;
60
- trailingSlash?: AddTraillingSlash1;
75
+ variables?: NavigationVariables;
61
76
  [k: string]: unknown;
62
77
  }[];
63
78
 
@@ -67,8 +82,7 @@ export type NavigationItems = {
67
82
  export interface InputData {
68
83
  title?: TitleSettings;
69
84
  route?: TitleNavigation;
70
- leadingSlash?: AddLeadingSlash;
71
- trailingSlash?: AddTraillingSlash;
85
+ variables?: TitleNavigationVariables;
72
86
  style?: ItemStyle;
73
87
  navItems?: NavigationItems;
74
88
  [k: string]: unknown;
@@ -15,19 +15,29 @@
15
15
  "description": "The destination path when the title/header is clicked. Use for navigating to a home or main page. Use relative paths or enable leadingSlash for absolute routing.",
16
16
  "type": "string"
17
17
  },
18
- "leadingSlash": {
19
- "title": "Add Leading Slash",
20
- "order": 4,
21
- "description": "When enabled, prepends '/' to the title's navigation route making it absolute from the root. When disabled, routes are relative to the current location.",
22
- "dataDrivenDisabled": true,
23
- "type": "boolean"
24
- },
25
- "trailingSlash": {
26
- "title": "Add Trailling Slash",
27
- "order": 5,
28
- "description": "When enabled, appends '/' to the end of the title's navigation route. Required by some routing configurations.",
18
+ "variables": {
19
+ "title": "Title Navigation Variables",
20
+ "description": "Array of variable definitions for dynamic route segment substitution. Each variable has a label (used in the route string as {{label}}) and a value (the replacement text). Values can be static or bound to data columns for real-time updates.",
21
+ "type": "array",
29
22
  "dataDrivenDisabled": true,
30
- "type": "boolean"
23
+ "order": 4,
24
+ "items": {
25
+ "type": "object",
26
+ "properties": {
27
+ "label": {
28
+ "title": "Label",
29
+ "description": "The variable name used in the route string. Reference this in your route using the {{label}} syntax. Use descriptive names like 'temperature', 'status', 'deviceName'.",
30
+ "type": "string",
31
+ "order": 1
32
+ },
33
+ "value": {
34
+ "title": "Value",
35
+ "description": "The replacement text that will appear in place of {{label}} in the rendered output. Can be a static value or bound to a data column for dynamic updates.",
36
+ "type": "string",
37
+ "order": 2
38
+ }
39
+ }
40
+ }
31
41
  },
32
42
  "style": {
33
43
  "title": "Item Style",
@@ -89,22 +99,32 @@
89
99
  "route": {
90
100
  "title": "Navigation Route",
91
101
  "order": 3,
92
- "description": "The destination path when this item is clicked. Use relative paths that append to the current URL, or enable leadingSlash for absolute routing.",
102
+ "description": "The destination path when this item is clicked. Supports two dynamic substitution mechanisms: (1) Variable placeholders using double curly braces — define variables in the 'Variables' array below and reference them as {{variableName}} in the route string (e.g., '/device/{{deviceId}}/details' where a variable with label 'deviceId' provides the value). (2) Wildcard segments using a single asterisk '*' as a full path segment — each '*' is replaced at runtime by the segment at the same position from the current browser route (e.g., '/*/settings' navigates to the settings page while preserving the first segment of the current URL). The '*' must be the entire segment to be substituted; partial wildcards like 'test*' are treated as literal text. Routes starting with '/' are absolute; routes without a leading slash are relative to the current location.",
93
103
  "type": "string"
94
104
  },
95
- "leadingSlash": {
96
- "title": "Add Leading Slash",
97
- "order": 4,
98
- "description": "When enabled, prepends '/' to this item's route making it absolute from the root.",
99
- "dataDrivenDisabled": true,
100
- "type": "boolean"
101
- },
102
- "trailingSlash": {
103
- "title": "Add Trailling Slash",
104
- "order": 5,
105
- "description": "When enabled, appends '/' to the end of this item's route.",
105
+ "variables": {
106
+ "title": "Navigation Variables",
107
+ "description": "Array of variable definitions for dynamic route segment substitution. Each variable has a label (used in the route string as {{label}}) and a value (the replacement text). Values can be static or bound to data columns for real-time updates.",
108
+ "type": "array",
106
109
  "dataDrivenDisabled": true,
107
- "type": "boolean"
110
+ "order": 4,
111
+ "items": {
112
+ "type": "object",
113
+ "properties": {
114
+ "label": {
115
+ "title": "Label",
116
+ "description": "The variable name used in the route string. Reference this in your route using the {{label}} syntax. Use descriptive names like 'temperature', 'status', 'deviceName'.",
117
+ "type": "string",
118
+ "order": 1
119
+ },
120
+ "value": {
121
+ "title": "Value",
122
+ "description": "The replacement text that will appear in place of {{label}} in the rendered output. Can be a static value or bound to a data column for dynamic updates.",
123
+ "type": "string",
124
+ "order": 2
125
+ }
126
+ }
127
+ }
108
128
  }
109
129
  }
110
130
  }
@@ -55,15 +55,28 @@ export class WidgetSidenav extends LitElement {
55
55
  return '/' + route.split('/').filter(Boolean).join('/')
56
56
  }
57
57
 
58
- addSlashes(item?: any): string | undefined {
59
- item.route = String(item.route)
60
- if (!item.route?.endsWith('/') && item.trailingSlash) {
61
- item.route += '/'
58
+ resolveRoute(item?: any): string | undefined {
59
+ let route = String(item?.route ?? '')
60
+ if (item?.variables) {
61
+ for (const variable of item.variables) {
62
+ if (variable.label) {
63
+ route = route
64
+ .split(`{{${variable.label}}}`)
65
+ .join(encodeURIComponent(String(variable.value ?? '')))
66
+ }
67
+ }
62
68
  }
63
- if (!item.route?.startsWith('/') && item.leadingSlash) {
64
- item.route = '/' + item.route
69
+ if (route.includes('*')) {
70
+ const currentSegments = (this.route || '').split('/').filter(Boolean)
71
+ const routeSegments = route.split('/').filter(Boolean)
72
+ for (let i = 0; i < routeSegments.length; i++) {
73
+ if (routeSegments[i] === '*') {
74
+ routeSegments[i] = currentSegments[i] ?? ''
75
+ }
76
+ }
77
+ route = (route.startsWith('/') ? '/' : '') + routeSegments.filter(Boolean).join('/')
65
78
  }
66
- return item.route
79
+ return route
67
80
  }
68
81
 
69
82
  matchesRoute(itemRoute?: string) {
@@ -148,7 +161,13 @@ export class WidgetSidenav extends LitElement {
148
161
  class="paging"
149
162
  style=${this.inputData?.route ? 'cursor: pointer' : ''}
150
163
  ?active=${this.inputData?.title}
151
- @click=${() => this.handleNavItemClick(this.addSlashes(this.inputData))}
164
+ @click=${() =>
165
+ this.handleNavItemClick(
166
+ this.resolveRoute({
167
+ route: this.inputData?.route,
168
+ variables: this.inputData?.variables
169
+ })
170
+ )}
152
171
  >
153
172
  ${this.inputData?.title}
154
173
  </h2>
@@ -158,9 +177,11 @@ export class WidgetSidenav extends LitElement {
158
177
  (item) => item.label,
159
178
  (item) => html`
160
179
  <div
161
- class="nav-item ${this.matchesRoute(this.addSlashes(item)) ? 'selected' : ''}"
180
+ class="nav-item ${this.matchesRoute(this.resolveRoute(item))
181
+ ? 'selected'
182
+ : ''}"
162
183
  style="gap: ${gap}px;"
163
- @click=${() => this.handleNavItemClick(this.addSlashes(item))}
184
+ @click=${() => this.handleNavItemClick(this.resolveRoute(item))}
164
185
  >
165
186
  ${item.iconName
166
187
  ? html`
package/thumbnail.webp ADDED
Binary file