@elavarasanbititude/ng-cwr-sidebar 1.0.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.
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `ng-cwr-sidebar` will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [1.0.0] - 2026-04-16
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `Sidebar` standalone Angular component (`<cwr-sidebar>`) with:
|
|
14
|
+
- Collapsible sidebar with configurable width
|
|
15
|
+
- Left/right positioning support
|
|
16
|
+
- Nested menu items with expand/collapse
|
|
17
|
+
- Badge support on menu items
|
|
18
|
+
- Configurable colors (background, text, hover)
|
|
19
|
+
- Mobile overlay mode
|
|
20
|
+
- Toggle button
|
|
21
|
+
- `menuItemClicked` and `collapsedChange` output events
|
|
22
|
+
- `SidebarService` for programmatic control:
|
|
23
|
+
- `toggleCollapsed()`, `setCollapsed()`, `getCollapsed()`
|
|
24
|
+
- `setMenuItems()`, `getMenuItems()`, `addMenuItem()`, `removeMenuItem()`
|
|
25
|
+
- `setConfig()`, `getConfig()`
|
|
26
|
+
- Observable streams: `collapsed$`, `menuItems$`, `config$`
|
|
27
|
+
- `SidebarMenuItem` and `SidebarConfig` TypeScript interfaces
|
|
28
|
+
- Full SCSS theming with CSS custom properties
|
package/README.md
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# @yourname/ng-cwr-sidebar
|
|
2
|
+
|
|
3
|
+
A modern, flexible, and fully customizable Angular sidebar component library built with Angular 21 and SCSS. Perfect for building responsive navigation sidebars with nested menus, icons, and badges.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✨ **Fully Customizable** - Configure colors, width, animations, and more
|
|
8
|
+
- 📱 **Responsive Design** - Works seamlessly on desktop and mobile devices
|
|
9
|
+
- 🎨 **Beautiful Styling** - Built with SCSS with light and dark theme support
|
|
10
|
+
- 🔀 **Nested Menus** - Support for multi-level menu hierarchies
|
|
11
|
+
- 🏷️ **Badges** - Add notification badges to menu items
|
|
12
|
+
- 🎯 **Collapsible** - Smooth collapse/expand animations
|
|
13
|
+
- ♿ **Accessible** - Built with accessibility best practices
|
|
14
|
+
- 🚀 **TypeScript** - Fully typed with TypeScript interfaces
|
|
15
|
+
- 🔄 **Reactive** - Built on RxJS Observables
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @yourname/ng-cwr-sidebar
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### 1. Import the Component
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { Sidebar } from '@yourname/ng-cwr-sidebar';
|
|
29
|
+
|
|
30
|
+
@Component({
|
|
31
|
+
selector: 'app-root',
|
|
32
|
+
standalone: true,
|
|
33
|
+
imports: [Sidebar, CommonModule],
|
|
34
|
+
template: `
|
|
35
|
+
<cwr-sidebar
|
|
36
|
+
[menuItems]="menuItems"
|
|
37
|
+
[config]="sidebarConfig"
|
|
38
|
+
(menuItemClicked)="onMenuItemClicked($event)"
|
|
39
|
+
></cwr-sidebar>
|
|
40
|
+
`,
|
|
41
|
+
})
|
|
42
|
+
export class AppComponent {
|
|
43
|
+
menuItems = [
|
|
44
|
+
{
|
|
45
|
+
label: 'Dashboard',
|
|
46
|
+
icon: '📊',
|
|
47
|
+
route: '/dashboard',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
label: 'Settings',
|
|
51
|
+
icon: '⚙️',
|
|
52
|
+
children: [
|
|
53
|
+
{ label: 'Profile', route: '/settings/profile' },
|
|
54
|
+
{ label: 'Preferences', route: '/settings/preferences' },
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
sidebarConfig = {
|
|
60
|
+
width: '250px',
|
|
61
|
+
collapsedWidth: '60px',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
onMenuItemClicked(item: any) {
|
|
65
|
+
console.log('Menu item clicked:', item);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Using the Sidebar Service
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { SidebarService } from '@yourname/ng-cwr-sidebar';
|
|
74
|
+
|
|
75
|
+
export class MyComponent {
|
|
76
|
+
constructor(private sidebarService: SidebarService) {}
|
|
77
|
+
|
|
78
|
+
toggleSidebar() {
|
|
79
|
+
this.sidebarService.toggleCollapsed();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
addMenuItem() {
|
|
83
|
+
this.sidebarService.addMenuItem({
|
|
84
|
+
id: 'new-item',
|
|
85
|
+
label: 'New Menu Item',
|
|
86
|
+
icon: '✨',
|
|
87
|
+
route: '/new',
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Configuration
|
|
94
|
+
|
|
95
|
+
### SidebarConfig Interface
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
interface SidebarConfig {
|
|
99
|
+
collapsed?: boolean; // Initially collapsed state
|
|
100
|
+
position?: 'left' | 'right'; // Sidebar position
|
|
101
|
+
width?: string; // Width when expanded (default: '250px')
|
|
102
|
+
collapsedWidth?: string; // Width when collapsed (default: '60px')
|
|
103
|
+
backgroundColor?: string; // Background color
|
|
104
|
+
textColor?: string; // Text color
|
|
105
|
+
hoverColor?: string; // Hover background color
|
|
106
|
+
toggleButton?: boolean; // Show toggle button (default: true)
|
|
107
|
+
overlayOnMobile?: boolean; // Show overlay on mobile (default: true)
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### SidebarMenuItem Interface
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
interface SidebarMenuItem {
|
|
115
|
+
id?: string; // Unique identifier
|
|
116
|
+
label: string; // Display label
|
|
117
|
+
icon?: string; // Icon (emoji or HTML)
|
|
118
|
+
route?: string; // Router link
|
|
119
|
+
action?: () => void; // Click action function
|
|
120
|
+
children?: SidebarMenuItem[]; // Nested menu items
|
|
121
|
+
disabled?: boolean; // Disable menu item
|
|
122
|
+
badge?: {
|
|
123
|
+
text: string;
|
|
124
|
+
color?: string; // Badge background color
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Examples
|
|
130
|
+
|
|
131
|
+
### Basic Menu
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const menuItems: SidebarMenuItem[] = [
|
|
135
|
+
{ label: 'Home', icon: '🏠', route: '/' },
|
|
136
|
+
{ label: 'About', icon: 'ℹ️', route: '/about' },
|
|
137
|
+
{ label: 'Contact', icon: '📧', route: '/contact' },
|
|
138
|
+
];
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Menu with Nested Items
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
const menuItems: SidebarMenuItem[] = [
|
|
145
|
+
{
|
|
146
|
+
label: 'Products',
|
|
147
|
+
icon: '📦',
|
|
148
|
+
children: [
|
|
149
|
+
{ label: 'Electronics', route: '/products/electronics' },
|
|
150
|
+
{ label: 'Clothing', route: '/products/clothing' },
|
|
151
|
+
{ label: 'Books', route: '/products/books' },
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
];
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Menu with Badges
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const menuItems: SidebarMenuItem[] = [
|
|
161
|
+
{
|
|
162
|
+
label: 'Messages',
|
|
163
|
+
icon: '💬',
|
|
164
|
+
route: '/messages',
|
|
165
|
+
badge: {
|
|
166
|
+
text: '5 new',
|
|
167
|
+
color: '#ff6b6b',
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
];
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Custom Actions
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
const menuItems: SidebarMenuItem[] = [
|
|
177
|
+
{
|
|
178
|
+
label: 'Logout',
|
|
179
|
+
icon: '🚪',
|
|
180
|
+
action: () => {
|
|
181
|
+
// Custom logout logic
|
|
182
|
+
console.log('Logging out...');
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
];
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Themed Configuration
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
// Light theme
|
|
192
|
+
const lightConfig: SidebarConfig = {
|
|
193
|
+
backgroundColor: '#f5f5f5',
|
|
194
|
+
textColor: '#333',
|
|
195
|
+
hoverColor: '#e0e0e0',
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// Dark theme
|
|
199
|
+
const darkConfig: SidebarConfig = {
|
|
200
|
+
backgroundColor: '#2c3e50',
|
|
201
|
+
textColor: '#ecf0f1',
|
|
202
|
+
hoverColor: '#34495e',
|
|
203
|
+
};
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Component API
|
|
207
|
+
|
|
208
|
+
### Input Properties
|
|
209
|
+
|
|
210
|
+
- `@Input() menuItems: SidebarMenuItem[]` - Array of menu items to display
|
|
211
|
+
- `@Input() config: SidebarConfig` - Configuration object for the sidebar
|
|
212
|
+
|
|
213
|
+
### Output Events
|
|
214
|
+
|
|
215
|
+
- `@Output() menuItemClicked: EventEmitter<SidebarMenuItem>` - Emits when a menu item is clicked
|
|
216
|
+
- `@Output() collapsedChange: EventEmitter<boolean>` - Emits when sidebar collapsed state changes
|
|
217
|
+
|
|
218
|
+
## Service API
|
|
219
|
+
|
|
220
|
+
### SidebarService
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
// Toggle collapsed state
|
|
224
|
+
sidebarService.toggleCollapsed(): void
|
|
225
|
+
|
|
226
|
+
// Set collapsed state
|
|
227
|
+
sidebarService.setCollapsed(collapsed: boolean): void
|
|
228
|
+
|
|
229
|
+
// Get collapsed state
|
|
230
|
+
sidebarService.getCollapsed(): boolean
|
|
231
|
+
|
|
232
|
+
// Get collapsed state as Observable
|
|
233
|
+
sidebarService.collapsed$: Observable<boolean>
|
|
234
|
+
|
|
235
|
+
// Set menu items
|
|
236
|
+
sidebarService.setMenuItems(items: SidebarMenuItem[]): void
|
|
237
|
+
|
|
238
|
+
// Get menu items
|
|
239
|
+
sidebarService.getMenuItems(): SidebarMenuItem[]
|
|
240
|
+
|
|
241
|
+
// Add a menu item
|
|
242
|
+
sidebarService.addMenuItem(item: SidebarMenuItem): void
|
|
243
|
+
|
|
244
|
+
// Remove a menu item by id
|
|
245
|
+
sidebarService.removeMenuItem(id: string): void
|
|
246
|
+
|
|
247
|
+
// Set configuration
|
|
248
|
+
sidebarService.setConfig(config: SidebarConfig): void
|
|
249
|
+
|
|
250
|
+
// Get configuration
|
|
251
|
+
sidebarService.getConfig(): SidebarConfig
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Styling
|
|
255
|
+
|
|
256
|
+
The component uses SCSS and includes both light and dark theme variants. You can customize the appearance by:
|
|
257
|
+
|
|
258
|
+
1. **Inline Styles** - Use the `config` input property
|
|
259
|
+
2. **CSS Classes** - Override default styles with your own CSS
|
|
260
|
+
3. **Dark Theme** - Add the `dark-theme` class to enable dark mode
|
|
261
|
+
|
|
262
|
+
### Custom Styling Example
|
|
263
|
+
|
|
264
|
+
```scss
|
|
265
|
+
// In your global styles
|
|
266
|
+
.cwr-sidebar {
|
|
267
|
+
--primary-color: #your-color;
|
|
268
|
+
|
|
269
|
+
.menu-link:hover {
|
|
270
|
+
background-color: rgba(0, 0, 0, 0.1);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Responsive Behavior
|
|
276
|
+
|
|
277
|
+
- **Desktop (>768px)**: Sidebar displays inline with toggle functionality
|
|
278
|
+
- **Mobile (<768px)**: Sidebar displays as overlay, can be toggled in/out of view
|
|
279
|
+
|
|
280
|
+
## Accessibility
|
|
281
|
+
|
|
282
|
+
- Full keyboard navigation support
|
|
283
|
+
- ARIA labels for screen readers
|
|
284
|
+
- Focus management
|
|
285
|
+
- Semantic HTML structure
|
|
286
|
+
|
|
287
|
+
## Browser Support
|
|
288
|
+
|
|
289
|
+
- Chrome (latest)
|
|
290
|
+
- Firefox (latest)
|
|
291
|
+
- Safari (latest)
|
|
292
|
+
- Edge (latest)
|
|
293
|
+
|
|
294
|
+
## License
|
|
295
|
+
|
|
296
|
+
MIT
|
|
297
|
+
|
|
298
|
+
## Contributing
|
|
299
|
+
|
|
300
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
301
|
+
|
|
302
|
+
## Support
|
|
303
|
+
|
|
304
|
+
For issues, questions, or suggestions, please open an issue on the [GitHub repository](https://github.com/yourusername/ng-cwr-sidebar/issues).
|
|
305
|
+
|
|
306
|
+
## Changelog
|
|
307
|
+
|
|
308
|
+
### Version 1.0.0
|
|
309
|
+
- Initial release
|
|
310
|
+
- Full sidebar component with nested menus
|
|
311
|
+
- Dark and light themes
|
|
312
|
+
- Responsive design
|
|
313
|
+
- Comprehensive service API
|
|
314
|
+
|
|
315
|
+
Once the project is built, you can publish your library by following these steps:
|
|
316
|
+
|
|
317
|
+
1. Navigate to the `dist` directory:
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
cd dist/ng-cwr-sidebar
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
2. Run the `npm publish` command to publish your library to the npm registry:
|
|
324
|
+
```bash
|
|
325
|
+
npm publish
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Running unit tests
|
|
329
|
+
|
|
330
|
+
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
ng test
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Running end-to-end tests
|
|
337
|
+
|
|
338
|
+
For end-to-end (e2e) testing, run:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
ng e2e
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
|
345
|
+
|
|
346
|
+
## Additional Resources
|
|
347
|
+
|
|
348
|
+
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Injectable, EventEmitter, inject, Output, Input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/common';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
import * as i2 from '@angular/router';
|
|
6
|
+
import { RouterModule } from '@angular/router';
|
|
7
|
+
import { BehaviorSubject } from 'rxjs';
|
|
8
|
+
|
|
9
|
+
class SidebarService {
|
|
10
|
+
collapsedSubject = new BehaviorSubject(false);
|
|
11
|
+
menuItemsSubject = new BehaviorSubject([]);
|
|
12
|
+
configSubject = new BehaviorSubject({});
|
|
13
|
+
collapsed$ = this.collapsedSubject.asObservable();
|
|
14
|
+
menuItems$ = this.menuItemsSubject.asObservable();
|
|
15
|
+
config$ = this.configSubject.asObservable();
|
|
16
|
+
constructor() { }
|
|
17
|
+
/**
|
|
18
|
+
* Toggle the sidebar collapsed state
|
|
19
|
+
*/
|
|
20
|
+
toggleCollapsed() {
|
|
21
|
+
this.collapsedSubject.next(!this.collapsedSubject.value);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Set the collapsed state
|
|
25
|
+
*/
|
|
26
|
+
setCollapsed(collapsed) {
|
|
27
|
+
this.collapsedSubject.next(collapsed);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get current collapsed state
|
|
31
|
+
*/
|
|
32
|
+
getCollapsed() {
|
|
33
|
+
return this.collapsedSubject.value;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Set menu items
|
|
37
|
+
*/
|
|
38
|
+
setMenuItems(items) {
|
|
39
|
+
this.menuItemsSubject.next(items);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get menu items
|
|
43
|
+
*/
|
|
44
|
+
getMenuItems() {
|
|
45
|
+
return this.menuItemsSubject.value;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Add a menu item
|
|
49
|
+
*/
|
|
50
|
+
addMenuItem(item) {
|
|
51
|
+
const items = this.menuItemsSubject.value;
|
|
52
|
+
this.menuItemsSubject.next([...items, item]);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Remove a menu item by id
|
|
56
|
+
*/
|
|
57
|
+
removeMenuItem(id) {
|
|
58
|
+
const items = this.menuItemsSubject.value.filter(item => item.id !== id);
|
|
59
|
+
this.menuItemsSubject.next(items);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Update sidebar configuration
|
|
63
|
+
*/
|
|
64
|
+
setConfig(config) {
|
|
65
|
+
this.configSubject.next(config);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get sidebar configuration
|
|
69
|
+
*/
|
|
70
|
+
getConfig() {
|
|
71
|
+
return this.configSubject.value;
|
|
72
|
+
}
|
|
73
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: SidebarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
74
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: SidebarService, providedIn: 'root' });
|
|
75
|
+
}
|
|
76
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: SidebarService, decorators: [{
|
|
77
|
+
type: Injectable,
|
|
78
|
+
args: [{
|
|
79
|
+
providedIn: 'root',
|
|
80
|
+
}]
|
|
81
|
+
}], ctorParameters: () => [] });
|
|
82
|
+
|
|
83
|
+
class Sidebar {
|
|
84
|
+
menuItems = [];
|
|
85
|
+
config = {};
|
|
86
|
+
menuItemClicked = new EventEmitter();
|
|
87
|
+
collapsedChange = new EventEmitter();
|
|
88
|
+
sidebarService = inject(SidebarService);
|
|
89
|
+
get collapsed$() {
|
|
90
|
+
return this.sidebarService.collapsed$;
|
|
91
|
+
}
|
|
92
|
+
expandedItems = new Set();
|
|
93
|
+
defaultConfig = {
|
|
94
|
+
collapsed: false,
|
|
95
|
+
position: 'left',
|
|
96
|
+
width: '250px',
|
|
97
|
+
collapsedWidth: '60px',
|
|
98
|
+
backgroundColor: '#f5f5f5',
|
|
99
|
+
textColor: '#333',
|
|
100
|
+
hoverColor: '#e0e0e0',
|
|
101
|
+
toggleButton: true,
|
|
102
|
+
overlayOnMobile: true,
|
|
103
|
+
};
|
|
104
|
+
ngOnInit() {
|
|
105
|
+
this.sidebarService.setMenuItems(this.menuItems);
|
|
106
|
+
const mergedConfig = { ...this.defaultConfig, ...this.config };
|
|
107
|
+
this.sidebarService.setConfig(mergedConfig);
|
|
108
|
+
}
|
|
109
|
+
ngOnChanges() {
|
|
110
|
+
if (this.menuItems.length > 0) {
|
|
111
|
+
this.sidebarService.setMenuItems(this.menuItems);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
toggleSidebar() {
|
|
115
|
+
this.sidebarService.toggleCollapsed();
|
|
116
|
+
this.collapsedChange.emit(this.sidebarService.getCollapsed());
|
|
117
|
+
}
|
|
118
|
+
toggleExpand(item) {
|
|
119
|
+
if (item.children && item.children.length > 0) {
|
|
120
|
+
const itemId = item.id || item.label;
|
|
121
|
+
if (this.expandedItems.has(itemId)) {
|
|
122
|
+
this.expandedItems.delete(itemId);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
this.expandedItems.add(itemId);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
isExpanded(item) {
|
|
130
|
+
const itemId = item.id || item.label;
|
|
131
|
+
return this.expandedItems.has(itemId);
|
|
132
|
+
}
|
|
133
|
+
onMenuItemClick(item) {
|
|
134
|
+
if (item.action) {
|
|
135
|
+
item.action();
|
|
136
|
+
}
|
|
137
|
+
this.menuItemClicked.emit(item);
|
|
138
|
+
}
|
|
139
|
+
hasCildren(item) {
|
|
140
|
+
return !!(item.children && item.children.length > 0);
|
|
141
|
+
}
|
|
142
|
+
getConfig() {
|
|
143
|
+
return this.sidebarService.getConfig();
|
|
144
|
+
}
|
|
145
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: Sidebar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
146
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.9", type: Sidebar, isStandalone: true, selector: "cwr-sidebar", inputs: { menuItems: "menuItems", config: "config" }, outputs: { menuItemClicked: "menuItemClicked", collapsedChange: "collapsedChange" }, usesOnChanges: true, ngImport: i0, template: "<div \n class=\"cwr-sidebar\"\n [ngClass]=\"{ 'collapsed': (collapsed$ | async) }\"\n [style.width]=\"(collapsed$ | async) ? getConfig().collapsedWidth : getConfig().width\"\n [style.backgroundColor]=\"getConfig().backgroundColor\"\n [style.color]=\"getConfig().textColor\"\n>\n <!-- Toggle Button -->\n <div class=\"sidebar-header\" *ngIf=\"getConfig().toggleButton\">\n <button \n class=\"toggle-btn\" \n (click)=\"toggleSidebar()\"\n [attr.aria-label]=\"(collapsed$ | async) ? 'Expand sidebar' : 'Collapse sidebar'\"\n >\n <span class=\"toggle-icon\">\u2630</span>\n </button>\n <span class=\"header-title\" *ngIf=\"!(collapsed$ | async)\">Menu</span>\n </div>\n\n <!-- Menu Items -->\n <nav class=\"sidebar-nav\">\n <ul class=\"menu-list\">\n <li \n *ngFor=\"let item of menuItems\"\n class=\"menu-item\"\n [ngClass]=\"{ \n 'has-children': hasCildren(item),\n 'expanded': isExpanded(item),\n 'disabled': item.disabled\n }\"\n >\n <button \n class=\"menu-link\"\n [routerLink]=\"item.route\"\n (click)=\"onMenuItemClick(item)\"\n [disabled]=\"item.disabled\"\n >\n <span class=\"menu-icon\" *ngIf=\"item.icon\">{{ item.icon }}</span>\n <span class=\"menu-label\" *ngIf=\"!(collapsed$ | async)\">\n {{ item.label }}\n </span>\n <span \n class=\"menu-badge\"\n *ngIf=\"item.badge && !(collapsed$ | async)\"\n [ngStyle]=\"{ 'background-color': item.badge.color || '#ff6b6b' }\"\n >\n {{ item.badge.text }}\n </span>\n <span \n class=\"expand-icon\"\n *ngIf=\"hasCildren(item)\"\n (click)=\"toggleExpand(item)\"\n [ngClass]=\"{ 'expanded': isExpanded(item) }\"\n >\n \u25BE\n </span>\n </button>\n\n <!-- Nested Menu Items -->\n <ul \n class=\"submenu-list\"\n *ngIf=\"hasCildren(item) && isExpanded(item)\"\n >\n <li \n *ngFor=\"let child of item.children\"\n class=\"submenu-item\"\n [ngClass]=\"{ 'disabled': child.disabled }\"\n >\n <button \n class=\"submenu-link\"\n [routerLink]=\"child.route\"\n (click)=\"onMenuItemClick(child)\"\n [disabled]=\"child.disabled\"\n >\n <span class=\"submenu-icon\" *ngIf=\"child.icon\">{{ child.icon }}</span>\n <span class=\"submenu-label\">{{ child.label }}</span>\n </button>\n </li>\n </ul>\n </li>\n </ul>\n </nav>\n</div>\n", styles: [".cwr-sidebar{display:flex;flex-direction:column;height:100vh;background-color:#f5f5f5;color:#333;border-right:1px solid #ddd;overflow:hidden;transition:width .3s ease-in-out;position:relative;z-index:1000}.cwr-sidebar.collapsed{width:60px}.cwr-sidebar .sidebar-header{display:flex;align-items:center;justify-content:space-between;padding:1rem;border-bottom:1px solid #ddd;background-color:#00000005}.cwr-sidebar .sidebar-header .toggle-btn{background:transparent;border:none;cursor:pointer;padding:.5rem;display:flex;align-items:center;justify-content:center;color:#333;font-size:1.2rem;transition:background-color .3s,color .3s;border-radius:4px}.cwr-sidebar .sidebar-header .toggle-btn:hover{background-color:#e0e0e0;color:#007bff}.cwr-sidebar .sidebar-header .toggle-btn:active{transform:scale(.95)}.cwr-sidebar .sidebar-header .toggle-btn .toggle-icon{display:block}.cwr-sidebar .sidebar-header .header-title{flex:1;margin-left:.5rem;font-weight:600;font-size:.95rem;text-transform:uppercase;letter-spacing:.5px}.cwr-sidebar .sidebar-nav{flex:1;overflow-y:auto;overflow-x:hidden;padding:.5rem 0}.cwr-sidebar .sidebar-nav::-webkit-scrollbar{width:6px}.cwr-sidebar .sidebar-nav::-webkit-scrollbar-track{background:transparent}.cwr-sidebar .sidebar-nav::-webkit-scrollbar-thumb{background:#ccc;border-radius:3px}.cwr-sidebar .sidebar-nav::-webkit-scrollbar-thumb:hover{background:#999}.cwr-sidebar .menu-list{list-style:none;padding:0;margin:0}.cwr-sidebar .menu-item{position:relative;transition:background-color .3s}.cwr-sidebar .menu-item.disabled{opacity:.5;cursor:not-allowed}.cwr-sidebar .menu-item:hover>.menu-link{background-color:#e0e0e0}.cwr-sidebar .menu-link{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.75rem 1rem;background:transparent;border:none;color:inherit;cursor:pointer;font-size:.95rem;text-align:left;transition:background-color .3s,color .3s;position:relative}.cwr-sidebar .menu-link:hover:not(:disabled){color:#007bff}.cwr-sidebar .menu-link:disabled{cursor:not-allowed}.cwr-sidebar .menu-link:focus{outline:2px solid #007bff;outline-offset:-2px}.cwr-sidebar .menu-link .menu-icon{display:flex;align-items:center;justify-content:center;min-width:24px;font-size:1.1rem;margin-right:.75rem}.cwr-sidebar .menu-link .menu-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cwr-sidebar .menu-link .menu-badge{display:inline-block;padding:.25rem .5rem;border-radius:12px;font-size:.75rem;font-weight:600;color:#fff;margin:0 .5rem;white-space:nowrap}.cwr-sidebar .menu-link .expand-icon{display:flex;align-items:center;justify-content:center;margin-left:.5rem;font-size:.75rem;transition:transform .3s;cursor:pointer}.cwr-sidebar .menu-link .expand-icon.expanded{transform:rotate(180deg)}.cwr-sidebar .submenu-list{list-style:none;padding:0;margin:0;background-color:#0000000d;max-height:none;overflow:visible;animation:slideDown .3s ease-in-out}.cwr-sidebar .submenu-item{position:relative;transition:background-color .3s}.cwr-sidebar .submenu-item.disabled{opacity:.5;cursor:not-allowed}.cwr-sidebar .submenu-item:hover>.submenu-link{background-color:#00000014}.cwr-sidebar .submenu-link{display:flex;align-items:center;width:100%;padding:.6rem 1rem .6rem 3rem;background:transparent;border:none;color:inherit;cursor:pointer;font-size:.9rem;text-align:left;transition:background-color .3s,color .3s}.cwr-sidebar .submenu-link:hover:not(:disabled){color:#007bff;background-color:#00000014}.cwr-sidebar .submenu-link:disabled{cursor:not-allowed}.cwr-sidebar .submenu-link:focus{outline:2px solid #007bff;outline-offset:-2px}.cwr-sidebar .submenu-link .submenu-icon{display:flex;align-items:center;justify-content:center;min-width:20px;font-size:1rem;margin-right:.75rem}.cwr-sidebar .submenu-link .submenu-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@media(max-width:768px){.cwr-sidebar{position:absolute;left:0;top:0;bottom:0;box-shadow:0 2px 10px #0003}.cwr-sidebar.collapsed{transform:translate(-100%);width:250px}.cwr-sidebar .sidebar-nav{height:calc(100vh - 60px)}}.cwr-sidebar{--sidebar-color: #f5f5f5;--text-color: #333}.cwr-sidebar .menu-link,.cwr-sidebar .submenu-link{color:var(--text-color)}.cwr-sidebar .menu-link:hover:not(:disabled),.cwr-sidebar .submenu-link:hover:not(:disabled){background-color:#0000000d}.cwr-sidebar.dark-theme{background-color:#2c3e50;color:#ecf0f1;border-right-color:#34495e}.cwr-sidebar.dark-theme .sidebar-header{background-color:#ffffff0d;border-bottom-color:#34495e}.cwr-sidebar.dark-theme .menu-link:hover{background-color:#ffffff1a}.cwr-sidebar.dark-theme .menu-link:focus{outline-color:#3498db}.cwr-sidebar.dark-theme .submenu-list{background-color:#0000004d}.cwr-sidebar.dark-theme .submenu-item:hover>.submenu-link{background-color:#ffffff1a}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
147
|
+
}
|
|
148
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: Sidebar, decorators: [{
|
|
149
|
+
type: Component,
|
|
150
|
+
args: [{ selector: 'cwr-sidebar', standalone: true, imports: [CommonModule, RouterModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div \n class=\"cwr-sidebar\"\n [ngClass]=\"{ 'collapsed': (collapsed$ | async) }\"\n [style.width]=\"(collapsed$ | async) ? getConfig().collapsedWidth : getConfig().width\"\n [style.backgroundColor]=\"getConfig().backgroundColor\"\n [style.color]=\"getConfig().textColor\"\n>\n <!-- Toggle Button -->\n <div class=\"sidebar-header\" *ngIf=\"getConfig().toggleButton\">\n <button \n class=\"toggle-btn\" \n (click)=\"toggleSidebar()\"\n [attr.aria-label]=\"(collapsed$ | async) ? 'Expand sidebar' : 'Collapse sidebar'\"\n >\n <span class=\"toggle-icon\">\u2630</span>\n </button>\n <span class=\"header-title\" *ngIf=\"!(collapsed$ | async)\">Menu</span>\n </div>\n\n <!-- Menu Items -->\n <nav class=\"sidebar-nav\">\n <ul class=\"menu-list\">\n <li \n *ngFor=\"let item of menuItems\"\n class=\"menu-item\"\n [ngClass]=\"{ \n 'has-children': hasCildren(item),\n 'expanded': isExpanded(item),\n 'disabled': item.disabled\n }\"\n >\n <button \n class=\"menu-link\"\n [routerLink]=\"item.route\"\n (click)=\"onMenuItemClick(item)\"\n [disabled]=\"item.disabled\"\n >\n <span class=\"menu-icon\" *ngIf=\"item.icon\">{{ item.icon }}</span>\n <span class=\"menu-label\" *ngIf=\"!(collapsed$ | async)\">\n {{ item.label }}\n </span>\n <span \n class=\"menu-badge\"\n *ngIf=\"item.badge && !(collapsed$ | async)\"\n [ngStyle]=\"{ 'background-color': item.badge.color || '#ff6b6b' }\"\n >\n {{ item.badge.text }}\n </span>\n <span \n class=\"expand-icon\"\n *ngIf=\"hasCildren(item)\"\n (click)=\"toggleExpand(item)\"\n [ngClass]=\"{ 'expanded': isExpanded(item) }\"\n >\n \u25BE\n </span>\n </button>\n\n <!-- Nested Menu Items -->\n <ul \n class=\"submenu-list\"\n *ngIf=\"hasCildren(item) && isExpanded(item)\"\n >\n <li \n *ngFor=\"let child of item.children\"\n class=\"submenu-item\"\n [ngClass]=\"{ 'disabled': child.disabled }\"\n >\n <button \n class=\"submenu-link\"\n [routerLink]=\"child.route\"\n (click)=\"onMenuItemClick(child)\"\n [disabled]=\"child.disabled\"\n >\n <span class=\"submenu-icon\" *ngIf=\"child.icon\">{{ child.icon }}</span>\n <span class=\"submenu-label\">{{ child.label }}</span>\n </button>\n </li>\n </ul>\n </li>\n </ul>\n </nav>\n</div>\n", styles: [".cwr-sidebar{display:flex;flex-direction:column;height:100vh;background-color:#f5f5f5;color:#333;border-right:1px solid #ddd;overflow:hidden;transition:width .3s ease-in-out;position:relative;z-index:1000}.cwr-sidebar.collapsed{width:60px}.cwr-sidebar .sidebar-header{display:flex;align-items:center;justify-content:space-between;padding:1rem;border-bottom:1px solid #ddd;background-color:#00000005}.cwr-sidebar .sidebar-header .toggle-btn{background:transparent;border:none;cursor:pointer;padding:.5rem;display:flex;align-items:center;justify-content:center;color:#333;font-size:1.2rem;transition:background-color .3s,color .3s;border-radius:4px}.cwr-sidebar .sidebar-header .toggle-btn:hover{background-color:#e0e0e0;color:#007bff}.cwr-sidebar .sidebar-header .toggle-btn:active{transform:scale(.95)}.cwr-sidebar .sidebar-header .toggle-btn .toggle-icon{display:block}.cwr-sidebar .sidebar-header .header-title{flex:1;margin-left:.5rem;font-weight:600;font-size:.95rem;text-transform:uppercase;letter-spacing:.5px}.cwr-sidebar .sidebar-nav{flex:1;overflow-y:auto;overflow-x:hidden;padding:.5rem 0}.cwr-sidebar .sidebar-nav::-webkit-scrollbar{width:6px}.cwr-sidebar .sidebar-nav::-webkit-scrollbar-track{background:transparent}.cwr-sidebar .sidebar-nav::-webkit-scrollbar-thumb{background:#ccc;border-radius:3px}.cwr-sidebar .sidebar-nav::-webkit-scrollbar-thumb:hover{background:#999}.cwr-sidebar .menu-list{list-style:none;padding:0;margin:0}.cwr-sidebar .menu-item{position:relative;transition:background-color .3s}.cwr-sidebar .menu-item.disabled{opacity:.5;cursor:not-allowed}.cwr-sidebar .menu-item:hover>.menu-link{background-color:#e0e0e0}.cwr-sidebar .menu-link{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.75rem 1rem;background:transparent;border:none;color:inherit;cursor:pointer;font-size:.95rem;text-align:left;transition:background-color .3s,color .3s;position:relative}.cwr-sidebar .menu-link:hover:not(:disabled){color:#007bff}.cwr-sidebar .menu-link:disabled{cursor:not-allowed}.cwr-sidebar .menu-link:focus{outline:2px solid #007bff;outline-offset:-2px}.cwr-sidebar .menu-link .menu-icon{display:flex;align-items:center;justify-content:center;min-width:24px;font-size:1.1rem;margin-right:.75rem}.cwr-sidebar .menu-link .menu-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cwr-sidebar .menu-link .menu-badge{display:inline-block;padding:.25rem .5rem;border-radius:12px;font-size:.75rem;font-weight:600;color:#fff;margin:0 .5rem;white-space:nowrap}.cwr-sidebar .menu-link .expand-icon{display:flex;align-items:center;justify-content:center;margin-left:.5rem;font-size:.75rem;transition:transform .3s;cursor:pointer}.cwr-sidebar .menu-link .expand-icon.expanded{transform:rotate(180deg)}.cwr-sidebar .submenu-list{list-style:none;padding:0;margin:0;background-color:#0000000d;max-height:none;overflow:visible;animation:slideDown .3s ease-in-out}.cwr-sidebar .submenu-item{position:relative;transition:background-color .3s}.cwr-sidebar .submenu-item.disabled{opacity:.5;cursor:not-allowed}.cwr-sidebar .submenu-item:hover>.submenu-link{background-color:#00000014}.cwr-sidebar .submenu-link{display:flex;align-items:center;width:100%;padding:.6rem 1rem .6rem 3rem;background:transparent;border:none;color:inherit;cursor:pointer;font-size:.9rem;text-align:left;transition:background-color .3s,color .3s}.cwr-sidebar .submenu-link:hover:not(:disabled){color:#007bff;background-color:#00000014}.cwr-sidebar .submenu-link:disabled{cursor:not-allowed}.cwr-sidebar .submenu-link:focus{outline:2px solid #007bff;outline-offset:-2px}.cwr-sidebar .submenu-link .submenu-icon{display:flex;align-items:center;justify-content:center;min-width:20px;font-size:1rem;margin-right:.75rem}.cwr-sidebar .submenu-link .submenu-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@media(max-width:768px){.cwr-sidebar{position:absolute;left:0;top:0;bottom:0;box-shadow:0 2px 10px #0003}.cwr-sidebar.collapsed{transform:translate(-100%);width:250px}.cwr-sidebar .sidebar-nav{height:calc(100vh - 60px)}}.cwr-sidebar{--sidebar-color: #f5f5f5;--text-color: #333}.cwr-sidebar .menu-link,.cwr-sidebar .submenu-link{color:var(--text-color)}.cwr-sidebar .menu-link:hover:not(:disabled),.cwr-sidebar .submenu-link:hover:not(:disabled){background-color:#0000000d}.cwr-sidebar.dark-theme{background-color:#2c3e50;color:#ecf0f1;border-right-color:#34495e}.cwr-sidebar.dark-theme .sidebar-header{background-color:#ffffff0d;border-bottom-color:#34495e}.cwr-sidebar.dark-theme .menu-link:hover{background-color:#ffffff1a}.cwr-sidebar.dark-theme .menu-link:focus{outline-color:#3498db}.cwr-sidebar.dark-theme .submenu-list{background-color:#0000004d}.cwr-sidebar.dark-theme .submenu-item:hover>.submenu-link{background-color:#ffffff1a}\n"] }]
|
|
151
|
+
}], propDecorators: { menuItems: [{
|
|
152
|
+
type: Input
|
|
153
|
+
}], config: [{
|
|
154
|
+
type: Input
|
|
155
|
+
}], menuItemClicked: [{
|
|
156
|
+
type: Output
|
|
157
|
+
}], collapsedChange: [{
|
|
158
|
+
type: Output
|
|
159
|
+
}] } });
|
|
160
|
+
|
|
161
|
+
/*
|
|
162
|
+
* Public API Surface of ng-cwr-sidebar
|
|
163
|
+
*/
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Generated bundle index. Do not edit.
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
export { Sidebar, SidebarService };
|
|
170
|
+
//# sourceMappingURL=elavarasanbititude-ng-cwr-sidebar.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elavarasanbititude-ng-cwr-sidebar.mjs","sources":["../../../packages/ng-cwr-sidebar/src/lib/services/sidebar.service.ts","../../../packages/ng-cwr-sidebar/src/lib/sidebar/sidebar.ts","../../../packages/ng-cwr-sidebar/src/lib/sidebar/sidebar.html","../../../packages/ng-cwr-sidebar/src/public-api.ts","../../../packages/ng-cwr-sidebar/src/elavarasanbititude-ng-cwr-sidebar.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { BehaviorSubject, Observable } from 'rxjs';\nimport { SidebarConfig, SidebarMenuItem } from '../models/sidebar.model';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class SidebarService {\n private collapsedSubject = new BehaviorSubject<boolean>(false);\n private menuItemsSubject = new BehaviorSubject<SidebarMenuItem[]>([]);\n private configSubject = new BehaviorSubject<SidebarConfig>({});\n\n public collapsed$ = this.collapsedSubject.asObservable();\n public menuItems$ = this.menuItemsSubject.asObservable();\n public config$ = this.configSubject.asObservable();\n\n constructor() {}\n\n /**\n * Toggle the sidebar collapsed state\n */\n toggleCollapsed(): void {\n this.collapsedSubject.next(!this.collapsedSubject.value);\n }\n\n /**\n * Set the collapsed state\n */\n setCollapsed(collapsed: boolean): void {\n this.collapsedSubject.next(collapsed);\n }\n\n /**\n * Get current collapsed state\n */\n getCollapsed(): boolean {\n return this.collapsedSubject.value;\n }\n\n /**\n * Set menu items\n */\n setMenuItems(items: SidebarMenuItem[]): void {\n this.menuItemsSubject.next(items);\n }\n\n /**\n * Get menu items\n */\n getMenuItems(): SidebarMenuItem[] {\n return this.menuItemsSubject.value;\n }\n\n /**\n * Add a menu item\n */\n addMenuItem(item: SidebarMenuItem): void {\n const items = this.menuItemsSubject.value;\n this.menuItemsSubject.next([...items, item]);\n }\n\n /**\n * Remove a menu item by id\n */\n removeMenuItem(id: string): void {\n const items = this.menuItemsSubject.value.filter(item => item.id !== id);\n this.menuItemsSubject.next(items);\n }\n\n /**\n * Update sidebar configuration\n */\n setConfig(config: SidebarConfig): void {\n this.configSubject.next(config);\n }\n\n /**\n * Get sidebar configuration\n */\n getConfig(): SidebarConfig {\n return this.configSubject.value;\n }\n}\n","import { Component, OnInit, Input, Output, EventEmitter, ChangeDetectionStrategy, inject } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { RouterModule } from '@angular/router';\nimport { SidebarService } from '../services/sidebar.service';\nimport { SidebarConfig, SidebarMenuItem } from '../models/sidebar.model';\n\n@Component({\n selector: 'cwr-sidebar',\n standalone: true,\n imports: [CommonModule, RouterModule],\n templateUrl: './sidebar.html',\n styleUrl: './sidebar.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class Sidebar implements OnInit {\n @Input() menuItems: SidebarMenuItem[] = [];\n @Input() config: SidebarConfig = {};\n @Output() menuItemClicked = new EventEmitter<SidebarMenuItem>();\n @Output() collapsedChange = new EventEmitter<boolean>();\n\n private sidebarService = inject(SidebarService);\n\n get collapsed$() {\n return this.sidebarService.collapsed$;\n }\n\n expandedItems: Set<string> = new Set();\n\n readonly defaultConfig: SidebarConfig = {\n collapsed: false,\n position: 'left',\n width: '250px',\n collapsedWidth: '60px',\n backgroundColor: '#f5f5f5',\n textColor: '#333',\n hoverColor: '#e0e0e0',\n toggleButton: true,\n overlayOnMobile: true,\n };\n\n ngOnInit(): void {\n this.sidebarService.setMenuItems(this.menuItems);\n const mergedConfig = { ...this.defaultConfig, ...this.config };\n this.sidebarService.setConfig(mergedConfig);\n }\n\n ngOnChanges(): void {\n if (this.menuItems.length > 0) {\n this.sidebarService.setMenuItems(this.menuItems);\n }\n }\n\n toggleSidebar(): void {\n this.sidebarService.toggleCollapsed();\n this.collapsedChange.emit(this.sidebarService.getCollapsed());\n }\n\n toggleExpand(item: SidebarMenuItem): void {\n if (item.children && item.children.length > 0) {\n const itemId = item.id || item.label;\n if (this.expandedItems.has(itemId)) {\n this.expandedItems.delete(itemId);\n } else {\n this.expandedItems.add(itemId);\n }\n }\n }\n\n isExpanded(item: SidebarMenuItem): boolean {\n const itemId = item.id || item.label;\n return this.expandedItems.has(itemId);\n }\n\n onMenuItemClick(item: SidebarMenuItem): void {\n if (item.action) {\n item.action();\n }\n this.menuItemClicked.emit(item);\n }\n\n hasCildren(item: SidebarMenuItem): boolean {\n return !!(item.children && item.children.length > 0);\n }\n\n getConfig(): SidebarConfig {\n return this.sidebarService.getConfig();\n }\n}\n","<div \n class=\"cwr-sidebar\"\n [ngClass]=\"{ 'collapsed': (collapsed$ | async) }\"\n [style.width]=\"(collapsed$ | async) ? getConfig().collapsedWidth : getConfig().width\"\n [style.backgroundColor]=\"getConfig().backgroundColor\"\n [style.color]=\"getConfig().textColor\"\n>\n <!-- Toggle Button -->\n <div class=\"sidebar-header\" *ngIf=\"getConfig().toggleButton\">\n <button \n class=\"toggle-btn\" \n (click)=\"toggleSidebar()\"\n [attr.aria-label]=\"(collapsed$ | async) ? 'Expand sidebar' : 'Collapse sidebar'\"\n >\n <span class=\"toggle-icon\">☰</span>\n </button>\n <span class=\"header-title\" *ngIf=\"!(collapsed$ | async)\">Menu</span>\n </div>\n\n <!-- Menu Items -->\n <nav class=\"sidebar-nav\">\n <ul class=\"menu-list\">\n <li \n *ngFor=\"let item of menuItems\"\n class=\"menu-item\"\n [ngClass]=\"{ \n 'has-children': hasCildren(item),\n 'expanded': isExpanded(item),\n 'disabled': item.disabled\n }\"\n >\n <button \n class=\"menu-link\"\n [routerLink]=\"item.route\"\n (click)=\"onMenuItemClick(item)\"\n [disabled]=\"item.disabled\"\n >\n <span class=\"menu-icon\" *ngIf=\"item.icon\">{{ item.icon }}</span>\n <span class=\"menu-label\" *ngIf=\"!(collapsed$ | async)\">\n {{ item.label }}\n </span>\n <span \n class=\"menu-badge\"\n *ngIf=\"item.badge && !(collapsed$ | async)\"\n [ngStyle]=\"{ 'background-color': item.badge.color || '#ff6b6b' }\"\n >\n {{ item.badge.text }}\n </span>\n <span \n class=\"expand-icon\"\n *ngIf=\"hasCildren(item)\"\n (click)=\"toggleExpand(item)\"\n [ngClass]=\"{ 'expanded': isExpanded(item) }\"\n >\n ▾\n </span>\n </button>\n\n <!-- Nested Menu Items -->\n <ul \n class=\"submenu-list\"\n *ngIf=\"hasCildren(item) && isExpanded(item)\"\n >\n <li \n *ngFor=\"let child of item.children\"\n class=\"submenu-item\"\n [ngClass]=\"{ 'disabled': child.disabled }\"\n >\n <button \n class=\"submenu-link\"\n [routerLink]=\"child.route\"\n (click)=\"onMenuItemClick(child)\"\n [disabled]=\"child.disabled\"\n >\n <span class=\"submenu-icon\" *ngIf=\"child.icon\">{{ child.icon }}</span>\n <span class=\"submenu-label\">{{ child.label }}</span>\n </button>\n </li>\n </ul>\n </li>\n </ul>\n </nav>\n</div>\n","/*\n * Public API Surface of ng-cwr-sidebar\n */\n\nexport * from './lib/sidebar/sidebar';\nexport * from './lib/services/sidebar.service';\nexport * from './lib/models/sidebar.model';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elavarasanbititude/ng-cwr-sidebar",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A modern, flexible, and customizable Angular sidebar component library",
|
|
5
|
+
"author": "elavarasanbititude",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/yourusername/ng-cwr-sidebar"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/yourusername/ng-cwr-sidebar/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/yourusername/ng-cwr-sidebar#readme",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"angular",
|
|
17
|
+
"sidebar",
|
|
18
|
+
"navigation",
|
|
19
|
+
"menu",
|
|
20
|
+
"component",
|
|
21
|
+
"responsive",
|
|
22
|
+
"scss"
|
|
23
|
+
],
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@angular/common": "^21.2.0",
|
|
26
|
+
"@angular/core": "^21.2.0",
|
|
27
|
+
"@angular/router": "^21.2.0",
|
|
28
|
+
"rxjs": "~7.8.0"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"tslib": "^2.3.0"
|
|
32
|
+
},
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"module": "fesm2022/elavarasanbititude-ng-cwr-sidebar.mjs",
|
|
38
|
+
"typings": "types/elavarasanbititude-ng-cwr-sidebar.d.ts",
|
|
39
|
+
"exports": {
|
|
40
|
+
"./package.json": {
|
|
41
|
+
"default": "./package.json"
|
|
42
|
+
},
|
|
43
|
+
".": {
|
|
44
|
+
"types": "./types/elavarasanbititude-ng-cwr-sidebar.d.ts",
|
|
45
|
+
"default": "./fesm2022/elavarasanbititude-ng-cwr-sidebar.mjs"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"type": "module"
|
|
49
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import * as rxjs from 'rxjs';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { OnInit, EventEmitter } from '@angular/core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Represents a menu item in the sidebar
|
|
8
|
+
*/
|
|
9
|
+
interface SidebarMenuItem {
|
|
10
|
+
id?: string;
|
|
11
|
+
label: string;
|
|
12
|
+
icon?: string;
|
|
13
|
+
route?: string;
|
|
14
|
+
action?: () => void;
|
|
15
|
+
children?: SidebarMenuItem[];
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
badge?: {
|
|
18
|
+
text: string;
|
|
19
|
+
color?: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Configuration for the sidebar component
|
|
24
|
+
*/
|
|
25
|
+
interface SidebarConfig {
|
|
26
|
+
collapsed?: boolean;
|
|
27
|
+
position?: 'left' | 'right';
|
|
28
|
+
width?: string;
|
|
29
|
+
collapsedWidth?: string;
|
|
30
|
+
backgroundColor?: string;
|
|
31
|
+
textColor?: string;
|
|
32
|
+
hoverColor?: string;
|
|
33
|
+
toggleButton?: boolean;
|
|
34
|
+
overlayOnMobile?: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
declare class Sidebar implements OnInit {
|
|
38
|
+
menuItems: SidebarMenuItem[];
|
|
39
|
+
config: SidebarConfig;
|
|
40
|
+
menuItemClicked: EventEmitter<SidebarMenuItem>;
|
|
41
|
+
collapsedChange: EventEmitter<boolean>;
|
|
42
|
+
private sidebarService;
|
|
43
|
+
get collapsed$(): rxjs.Observable<boolean>;
|
|
44
|
+
expandedItems: Set<string>;
|
|
45
|
+
readonly defaultConfig: SidebarConfig;
|
|
46
|
+
ngOnInit(): void;
|
|
47
|
+
ngOnChanges(): void;
|
|
48
|
+
toggleSidebar(): void;
|
|
49
|
+
toggleExpand(item: SidebarMenuItem): void;
|
|
50
|
+
isExpanded(item: SidebarMenuItem): boolean;
|
|
51
|
+
onMenuItemClick(item: SidebarMenuItem): void;
|
|
52
|
+
hasCildren(item: SidebarMenuItem): boolean;
|
|
53
|
+
getConfig(): SidebarConfig;
|
|
54
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<Sidebar, never>;
|
|
55
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<Sidebar, "cwr-sidebar", never, { "menuItems": { "alias": "menuItems"; "required": false; }; "config": { "alias": "config"; "required": false; }; }, { "menuItemClicked": "menuItemClicked"; "collapsedChange": "collapsedChange"; }, never, never, true, never>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
declare class SidebarService {
|
|
59
|
+
private collapsedSubject;
|
|
60
|
+
private menuItemsSubject;
|
|
61
|
+
private configSubject;
|
|
62
|
+
collapsed$: Observable<boolean>;
|
|
63
|
+
menuItems$: Observable<SidebarMenuItem[]>;
|
|
64
|
+
config$: Observable<SidebarConfig>;
|
|
65
|
+
constructor();
|
|
66
|
+
/**
|
|
67
|
+
* Toggle the sidebar collapsed state
|
|
68
|
+
*/
|
|
69
|
+
toggleCollapsed(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Set the collapsed state
|
|
72
|
+
*/
|
|
73
|
+
setCollapsed(collapsed: boolean): void;
|
|
74
|
+
/**
|
|
75
|
+
* Get current collapsed state
|
|
76
|
+
*/
|
|
77
|
+
getCollapsed(): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Set menu items
|
|
80
|
+
*/
|
|
81
|
+
setMenuItems(items: SidebarMenuItem[]): void;
|
|
82
|
+
/**
|
|
83
|
+
* Get menu items
|
|
84
|
+
*/
|
|
85
|
+
getMenuItems(): SidebarMenuItem[];
|
|
86
|
+
/**
|
|
87
|
+
* Add a menu item
|
|
88
|
+
*/
|
|
89
|
+
addMenuItem(item: SidebarMenuItem): void;
|
|
90
|
+
/**
|
|
91
|
+
* Remove a menu item by id
|
|
92
|
+
*/
|
|
93
|
+
removeMenuItem(id: string): void;
|
|
94
|
+
/**
|
|
95
|
+
* Update sidebar configuration
|
|
96
|
+
*/
|
|
97
|
+
setConfig(config: SidebarConfig): void;
|
|
98
|
+
/**
|
|
99
|
+
* Get sidebar configuration
|
|
100
|
+
*/
|
|
101
|
+
getConfig(): SidebarConfig;
|
|
102
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SidebarService, never>;
|
|
103
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<SidebarService>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export { Sidebar, SidebarService };
|
|
107
|
+
export type { SidebarConfig, SidebarMenuItem };
|