Skip to content

Commit bd0dde8

Browse files
authored
Merge pull request #357 from six-group/feature/six-sidebar-improvement
feat: improve six-sidebar component
2 parents 77a508a + cd55b13 commit bd0dde8

30 files changed

+363
-26
lines changed

docs/changelog.md

+5
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
1414
`six-datepicker`.
1515

1616
- [Documentation](guide/angular.md) for using web components with Angular's standalone bootstrapping
17+
- `ActiveSidebarItemGroupDirective` and `ActiveSidebarItemDirective`: Added optional angular sidebar
18+
helper directives. See the [Angular guide](guide/angular.md) for more information.
19+
- Added nested sidbar menu to the angular demo application to showcase the helper directives
1720
- `six-header-dropdown`: Added `filter` and `filterPlaceholder` properties.
1821
- `six-header-menu-button`: Added `caret`, `disabled`, `loading`, `submit` and `reset` properties.
1922
- `six-header-menu-button`: Added `suffix` and `prefix` slots.
23+
- `six-sidebar-item` : added icon property analog to `six-sidebar-item-group`
2024

2125
### Fixed
2226

2327
- `six-logo`: removed inline style tag
2428
- `six-timepicker`: removed unnecessary bottom padding
2529
- `six-button` : simplify use of prefix and suffix icons
30+
- `six-sidebar-item-group`: fixed spacing for sub items
2631

2732
### Removed
2833

docs/components/six-icon.md

+2
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ Enter an icon label and press enter to display an icon:
283283
- [six-menu-item](six-menu-item.html)
284284
- [six-search-field](six-search-field.html)
285285
- [six-select](six-select.html)
286+
- [six-sidebar-item](six-sidebar-item.html)
286287
- [six-sidebar-item-group](six-sidebar-item-group.html)
287288
- [six-stage-indicator](six-stage-indicator.html)
288289
- [six-tile](six-tile.html)
@@ -304,6 +305,7 @@ graph TD;
304305
six-menu-item --> six-icon
305306
six-search-field --> six-icon
306307
six-select --> six-icon
308+
six-sidebar-item --> six-icon
307309
six-sidebar-item-group --> six-icon
308310
six-stage-indicator --> six-icon
309311
six-tile --> six-icon

docs/components/six-sidebar-item-group.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
```html
99
<div style="max-width: 20rem; padding: 1rem">
1010
<six-sidebar-item-group icon="description" name="Upload" value="upload">
11-
<six-sidebar-item value="data">Data</six-sidebar-item>
12-
<six-sidebar-item value="history">History</six-sidebar-item>
11+
<six-sidebar-item value="data" icon="analytics">Data</six-sidebar-item>
12+
<six-sidebar-item value="history" icon="history">History</six-sidebar-item>
1313
<six-sidebar-item-group icon="settings" name="Settings">
1414
<six-sidebar-item value="data">Data</six-sidebar-item>
1515
<six-sidebar-item value="history">History</six-sidebar-item>

docs/components/six-sidebar-item.md

+29
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@
1616
```
1717

1818

19+
## six sidebar item with icons
20+
21+
<docs-demo-six-sidebar-item-1></docs-demo-six-sidebar-item-1>
22+
23+
```html
24+
<div style="width: 10em" id="six-sidebar-items-icon">
25+
<six-sidebar-item icon="description">Data</six-sidebar-item>
26+
<six-sidebar-item icon="history">History</six-sidebar-item>
27+
<six-sidebar-item icon="account_balance">Transactions</six-sidebar-item>
28+
<six-sidebar-item icon="upload">Upload</six-sidebar-item>
29+
<six-sidebar-item icon="link" href="http://www.google.ch">Link</six-sidebar-item>
30+
</div>
31+
```
32+
33+
1934

2035
<!-- Auto Generated Below -->
2136

@@ -26,6 +41,7 @@
2641
| ---------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ----------- |
2742
| `disabled` | `disabled` | Set to true to draw the sidebar item in a disabled state. | `boolean` | `false` |
2843
| `href` | `href` | Provide if the item should be rendered as anchor tag. Note, that the href is added automatically when using routerLink in Angular. | `string \| undefined` | `undefined` |
44+
| `icon` | `icon` | Icon of the item | `string` | `''` |
2945
| `selected` | `selected` | Set to true to draw the item in a selected state. | `boolean` | `false` |
3046
| `value` | `value` | A unique value to store in the sidebar item. This can be used as a way to identify sidebar items when selected. | `string` | `''` |
3147

@@ -37,6 +53,19 @@
3753
| | Used to define the nested displayed text of the item. |
3854

3955

56+
## Dependencies
57+
58+
### Depends on
59+
60+
- [six-icon](six-icon.html)
61+
62+
### Graph
63+
```mermaid
64+
graph TD;
65+
six-sidebar-item --> six-icon
66+
style six-sidebar-item fill:#f9f,stroke:#333,stroke-width:4px
67+
```
68+
4069
----------------------------------------------
4170

4271
Copyright © 2021-present SIX-Group

docs/components/six-sidebar.md

+8-4
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@ six-sidebar allows to add a static sidebar to the left or right of the `six-root
1414
```html
1515
<six-sidebar position="left" width="20rem" open>
1616
<six-sidebar-item-group icon="description" name="Upload" value="upload">
17-
<six-sidebar-item value="data" disabled="true">Data</six-sidebar-item>
18-
<six-sidebar-item value="history">History</six-sidebar-item>
17+
<six-sidebar-item value="data" icon="analytics" disabled="true">Data</six-sidebar-item>
18+
<six-sidebar-item value="history" icon="history">History</six-sidebar-item>
1919
<six-sidebar-item-group icon="settings" name="Settings">
20-
<six-sidebar-item value="data" selected>Data</six-sidebar-item>
21-
<six-sidebar-item value="history">History</six-sidebar-item>
20+
<six-sidebar-item value="settingA" selected>Setting A</six-sidebar-item>
21+
<six-sidebar-item value="settingB">Setting B</six-sidebar-item>
22+
<six-sidebar-item-group icon="settings" name="Nested Settings">
23+
<six-sidebar-item value="sectionA" selected>Section A</six-sidebar-item>
24+
<six-sidebar-item value="sectionB">Section B</six-sidebar-item>
25+
</six-sidebar-item-group>
2226
</six-sidebar-item-group>
2327
</six-sidebar-item-group>
2428
<six-sidebar-item-group icon="task"

docs/examples/docs-demo-six-sidebar-0.vue

+8-4
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33

44
<six-sidebar position="left" width="20rem" open>
55
<six-sidebar-item-group icon="description" name="Upload" value="upload">
6-
<six-sidebar-item value="data" disabled="true">Data</six-sidebar-item>
7-
<six-sidebar-item value="history">History</six-sidebar-item>
6+
<six-sidebar-item value="data" icon="analytics" disabled="true">Data</six-sidebar-item>
7+
<six-sidebar-item value="history" icon="history">History</six-sidebar-item>
88
<six-sidebar-item-group icon="settings" name="Settings">
9-
<six-sidebar-item value="data" selected>Data</six-sidebar-item>
10-
<six-sidebar-item value="history">History</six-sidebar-item>
9+
<six-sidebar-item value="settingA" selected>Setting A</six-sidebar-item>
10+
<six-sidebar-item value="settingB">Setting B</six-sidebar-item>
11+
<six-sidebar-item-group icon="settings" name="Nested Settings">
12+
<six-sidebar-item value="sectionA" selected>Section A</six-sidebar-item>
13+
<six-sidebar-item value="sectionB">Section B</six-sidebar-item>
14+
</six-sidebar-item-group>
1115
</six-sidebar-item-group>
1216
</six-sidebar-item-group>
1317
<six-sidebar-item-group icon="task"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<template>
2+
<div>
3+
4+
<div style="width: 10em" id="six-sidebar-items-icon">
5+
<six-sidebar-item icon="description">Data</six-sidebar-item>
6+
<six-sidebar-item icon="history">History</six-sidebar-item>
7+
<six-sidebar-item icon="account_balance">Transactions</six-sidebar-item>
8+
<six-sidebar-item icon="upload">Upload</six-sidebar-item>
9+
<six-sidebar-item icon="link" href="http://www.google.ch">Link</six-sidebar-item>
10+
</div>
11+
12+
</div>
13+
</template>
14+
<style>
15+
16+
</style>
17+
<script>
18+
export default {
19+
name: 'docs-demo-six-sidebar-item-1',
20+
mounted() { }
21+
}
22+
</script>

docs/examples/docs-demo-six-sidebar-item-group-0.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
<div style="max-width: 20rem; padding: 1rem">
55
<six-sidebar-item-group icon="description" name="Upload" value="upload">
6-
<six-sidebar-item value="data">Data</six-sidebar-item>
7-
<six-sidebar-item value="history">History</six-sidebar-item>
6+
<six-sidebar-item value="data" icon="analytics">Data</six-sidebar-item>
7+
<six-sidebar-item value="history" icon="history">History</six-sidebar-item>
88
<six-sidebar-item-group icon="settings" name="Settings">
99
<six-sidebar-item value="data">Data</six-sidebar-item>
1010
<six-sidebar-item value="history">History</six-sidebar-item>

docs/guide/angular.md

+37
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,40 @@ Consult the
127127
[Angular example](https://github.com/six-group/six-webcomponents/tree/main/examples/angular) and the
128128
[source code documentation](https://github.com/six-group/six-webcomponents/blob/main/libraries/ui-library-angular/src/lib/form/six-form.directive.ts)
129129
of the `SixFormDirective` and for a more flexible alternative, the `SixFormUtilDirective`.
130+
131+
## Sidebar
132+
133+
The library provides Angular Router integration for the sidebar component through a set of
134+
directives that automatically manage the selection and expansion states based on the current route.
135+
136+
To enable router integration, add the `sixRouterLinkActive` attribute to the `six-sidebar`
137+
component. This activates three directives that work together:
138+
139+
- `ActiveSidebarDirective`: Enables route-based navigation in the sidebar
140+
- `ActiveSidebarItemDirective`: Automatically manages item selection based on the current route
141+
- `ActiveSidebarItemGroupDirective`: Automatically expands groups when they contain active routes
142+
143+
Example usage:
144+
145+
```html
146+
<!-- add sixRouterLinkActive to six-sidebar to include the sidebar helper directives -->
147+
<six-sidebar position="left" [open]="open" sixRouterLinkActive>
148+
<six-sidebar-item-group routerLink="/home" name="Home" icon="home"></six-sidebar-item-group>
149+
<six-sidebar-item-group routerLink="/form" name="Form" icon="assignment"></six-sidebar-item-group>
150+
<six-sidebar-item-group icon="settings" name="Settings">
151+
<six-sidebar-item routerLink="/settings/data" icon="analytics">Data</six-sidebar-item>
152+
<six-sidebar-item routerLink="/settings/history" icon="history">History</six-sidebar-item>
153+
</six-sidebar-item-group>
154+
</six-sidebar>
155+
```
156+
157+
When the router integration is enabled:
158+
159+
- Sidebar items are automatically selected when their route is active
160+
- Sidebar groups automatically expand when containing active routes
161+
- Manual selection state is preserved when no routes are active
162+
163+
Consult the
164+
[Angular example](https://github.com/six-group/six-webcomponents/tree/main/examples/angular) and the
165+
[source code documentation](https://github.com/six-group/six-webcomponents/blob/main/libraries/ui-library-angular/src/lib/sidebar/active-sidebar.directive.ts)
166+
of the `ActiveSidebarDirective`, `ActiveSidebarItemDirective` and `ActiveSidebarItemGroupDirective`.

docs/guide/upgrade-v5.md

+10
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ in the Angular example application, which covers most features.
9898
</six-button>
9999
```
100100

101+
## Angular specific upgrade (None Breaking Change)
102+
103+
- Angular Router integration for the `six-sidebar` component through a set of directives that
104+
automatically manage the selection and expansion states based on the current route.
105+
106+
To enable router integration, add the `sixRouterLinkActive` attribute to the `six-sidebar`
107+
component.
108+
109+
For more information and a usage example consult the [angular guide](angular.md#sidebar).
110+
101111
## Removed deprecated features (Breaking Change)
102112

103113
Refer to the _Removed_ section in the [changelog](../changelog.md).

examples/angular/src/app/app.module.ts

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { HeaderComponent } from './components/header/header.component';
1414
import { FormComponent } from './pages/form/form.component';
1515
import { AlertComponent } from './pages/alert/alert.component';
1616
import { DialogComponent } from './pages/dialog/dialog.component';
17+
import { SettingsComponent } from './pages/settings/settings.component';
1718

1819
@NgModule({
1920
declarations: [
@@ -25,6 +26,7 @@ import { DialogComponent } from './pages/dialog/dialog.component';
2526
FormComponent,
2627
AlertComponent,
2728
DialogComponent,
29+
SettingsComponent,
2830
],
2931
imports: [
3032
BrowserModule,

examples/angular/src/app/app.routes.ts

+9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { FormComponent } from './pages/form/form.component';
33
import { HomeComponent } from './pages/home/home.component';
44
import { AlertComponent } from './pages/alert/alert.component';
55
import { DialogComponent } from './pages/dialog/dialog.component';
6+
import { SettingsComponent } from './pages/settings/settings.component';
67

78
export const routes: Routes = [
89
{
@@ -26,4 +27,12 @@ export const routes: Routes = [
2627
path: 'dialog',
2728
component: DialogComponent,
2829
},
30+
{
31+
path: 'settings',
32+
children: [
33+
{ path: '', redirectTo: 'data', pathMatch: 'full' },
34+
{ path: 'data', component: SettingsComponent },
35+
{ path: 'history', component: SettingsComponent },
36+
],
37+
},
2938
];
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
<six-sidebar position="left" [open]="open">
1+
<six-sidebar position="left" [open]="open" sixRouterLinkActive>
22
<six-sidebar-item-group routerLink="/home" name="Home" icon="home"></six-sidebar-item-group>
33
<six-sidebar-item-group routerLink="/form" name="Form" icon="assignment"></six-sidebar-item-group>
44
<six-sidebar-item-group routerLink="/alert" name="Alert" icon="notifications_active"></six-sidebar-item-group>
55
<six-sidebar-item-group routerLink="/dialog" name="Dialog" icon="web_asset"></six-sidebar-item-group>
6+
<six-sidebar-item-group icon="settings" name="Settings">
7+
<six-sidebar-item routerLink="/settings/data" icon="analytics">Data</six-sidebar-item>
8+
<six-sidebar-item routerLink="/settings/history" icon="history">History</six-sidebar-item>
9+
</six-sidebar-item-group>
610
</six-sidebar>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Component, OnInit } from '@angular/core';
2+
import { ActivatedRoute } from '@angular/router';
3+
import { map } from 'rxjs';
4+
5+
@Component({
6+
selector: 'app-settings',
7+
template: ` <h1>This is the {{ settingsType$ | async }} settings</h1> `,
8+
})
9+
export class SettingsComponent {
10+
settingsType$ = this.route.url.pipe(map((segments) => segments[segments.length - 1].path));
11+
12+
constructor(private route: ActivatedRoute) {}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { ContentChildren, Directive, HostBinding, HostListener, inject, QueryList } from '@angular/core';
2+
import { RouterLinkActive } from '@angular/router';
3+
import { SixSidebarItem, SixSidebarItemGroup } from '../stencil-generated/components';
4+
5+
/**
6+
* Enables Angular router integration for the six-sidebar component.
7+
*
8+
* When this directive is added to a six-sidebar component using the 'sixRouterLinkActive' attribute,
9+
* it activates automatic route-based selection for sidebar items and groups.
10+
*
11+
* @recommended Add this directive to enable automatic route-based navigation in sidebars.
12+
*
13+
* @example
14+
* ```html
15+
* <six-sidebar sixRouterLinkActive>
16+
* <six-sidebar-item routerLink="/home">Home</six-sidebar-item>
17+
* <six-sidebar-item-group>
18+
* <six-sidebar-item routerLink="/settings/profile">Profile</six-sidebar-item>
19+
* </six-sidebar-item-group>
20+
* </six-sidebar>
21+
* ```
22+
*/
23+
@Directive({
24+
selector: 'six-sidebar[sixRouterLinkActive]',
25+
})
26+
export class ActiveSidebarDirective {}
27+
28+
/**
29+
* Enhances six-sidebar-item with Angular router integration.
30+
*
31+
* This directive automatically manages the 'selected' state of sidebar items based on the current route.
32+
* When used with ActiveSidebarDirective, it switches from manual selection to route-based selection.
33+
*
34+
* @requires RouterLinkActive
35+
* @optional ActiveSidebarDirective - If present, enables route-based selection
36+
*/
37+
@Directive({
38+
selector: 'six-sidebar-item',
39+
hostDirectives: [RouterLinkActive],
40+
})
41+
export class ActiveSidebarItemDirective {
42+
private routerLinkActive = inject(RouterLinkActive);
43+
44+
private sidebarItem = inject(SixSidebarItem);
45+
private activeSidebarDirective = inject(ActiveSidebarDirective, { optional: true });
46+
47+
@HostBinding('selected')
48+
get selected() {
49+
if (this.activeSidebarDirective == null) {
50+
return this.sidebarItem.selected;
51+
} else {
52+
return this.routerLinkActive.isActive;
53+
}
54+
}
55+
}
56+
57+
/**
58+
* Enhances six-sidebar-item-group with Angular router integration.
59+
*
60+
* This directive automatically manages the 'open' state of sidebar groups based on the active route.
61+
* When a child route is active, the group automatically expands to show the active item.
62+
*
63+
* @requires RouterLinkActive
64+
* @optional ActiveSidebarDirective - If present, enables route-based expansion
65+
*/
66+
@Directive({
67+
selector: 'six-sidebar-item-group',
68+
hostDirectives: [RouterLinkActive],
69+
})
70+
export class ActiveSidebarItemGroupDirective {
71+
private routerLinkActive = inject(RouterLinkActive);
72+
private sidebarItemGroup = inject(SixSidebarItemGroup);
73+
private activeSidebarDirective = inject(ActiveSidebarDirective, { optional: true });
74+
75+
@ContentChildren(SixSidebarItem) private sidebarItems!: QueryList<SixSidebarItem>;
76+
77+
@HostBinding('open')
78+
get open() {
79+
if (this.activeSidebarDirective == null) {
80+
return this.sidebarItemGroup.open;
81+
}
82+
83+
if (this.sidebarItems?.length > 0) {
84+
return this.routerLinkActive.isActive ? true : this.sidebarItemGroup.open;
85+
}
86+
87+
return this.routerLinkActive.isActive;
88+
}
89+
}

0 commit comments

Comments
 (0)