@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 };