@flusys/ng-layout 1.1.1-beta → 1.2.0-rc.1

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/README.md CHANGED
@@ -1,657 +1,101 @@
1
- # @flusys/ng-layout Package Guide
1
+ # @flusys/ng-layout
2
2
 
3
- ## Overview
3
+ Application shell for the FLUSYS Angular platform — topbar, sidebar, menu, and signal-based layout state management.
4
4
 
5
- `@flusys/ng-layout` provides the application shell, menu system, theme management, and layout components for FLUSYS applications. This package creates the visual structure and navigation framework.
5
+ [![npm version](https://img.shields.io/npm/v/@flusys/ng-layout.svg)](https://www.npmjs.com/package/@flusys/ng-layout)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
7
 
7
- **Key Principle:** ng-layout depends on ng-core and ng-shared, but remains independent of feature packages like ng-auth.
8
-
9
- ## Package Information
10
-
11
- - **Package:** `@flusys/ng-layout`
12
- - **Dependencies:** ng-core, ng-shared
13
- - **Dependents:** flusysng
14
- - **Build Command:** `npm run build:ng-layout`
15
-
16
- ## Features
17
-
18
- ### 1. App Layout Components
19
-
20
- #### AppLayout
21
-
22
- Main layout wrapper with signal-based state management.
8
+ ---
23
9
 
24
- ```typescript
25
- import { AppLayout } from '@flusys/ng-layout';
10
+ ## Installation
26
11
 
27
- @Component({
28
- selector: 'app-root',
29
- standalone: true,
30
- imports: [AppLayout],
31
- template: `
32
- <app-layout>
33
- <router-outlet />
34
- </app-layout>
35
- `
36
- })
37
- export class AppComponent {}
12
+ ```bash
13
+ npm install @flusys/ng-layout @flusys/ng-core @flusys/ng-shared
38
14
  ```
39
15
 
40
- **What it includes:**
41
- - AppTopbar (header with logo, user menu)
42
- - AppSidebar (collapsible navigation menu)
43
- - Main content area with `<router-outlet>`
44
- - AppFooter
45
-
46
- **Layout modes:**
47
- - **Static** - Sidebar always visible on desktop, overlay on mobile
48
- - **Overlay** - Sidebar overlays content when opened
49
-
50
- #### AppTopbar
51
-
52
- Application header with branding and user actions. Used automatically by AppLayout.
53
-
54
- **Features:**
55
- - Company name display (from `LAYOUT_AUTH_STATE` or fallback to "Flusys")
56
- - Menu toggle button (calls `layoutService.onMenuToggle()`)
57
- - Dark mode toggle button
58
- - Theme/color palette configurator (AppConfigurator via pStyleClass)
59
- - App launcher grid (if apps configured via `LayoutService.setApps()`)
60
- - Company/Branch selector (if `enableCompanyFeature` is true)
61
- - User profile dropdown (AppProfile)
62
-
63
- #### AppSidebar
64
-
65
- Collapsible navigation sidebar. Contains AppMenu.
66
-
67
- **Features:**
68
- - Multi-level menu via AppMenu
69
- - Collapsible/expandable
70
- - Active route highlighting
71
- - Icons with labels
72
- - Smooth CSS animations
73
-
74
- #### AppMenu
75
-
76
- Menu container that renders `LayoutService.menu` signal (permission-filtered).
77
-
78
- #### AppMenuitem
79
-
80
- Recursive menu item component using attribute selector `[app-menuitem]`.
81
-
82
- **Features:**
83
- - Nested children with toggle animation
84
- - Router link active detection with smart path matching
85
- - Menu state synchronization via `layoutService.menuSource$`
86
- - Smooth submenu collapse/expand via CSS transitions (no `@angular/animations`)
87
-
88
- #### AppFooter
89
-
90
- Displays company name (from `LAYOUT_AUTH_STATE`) or app name fallback.
91
-
92
- #### AppProfile
93
-
94
- User profile dropdown in topbar.
95
-
96
- **Features:**
97
- - User info display (picture, name, email)
98
- - Profile route link
99
- - Copy SignUp Link button (generates link with company slug)
100
- - Logout button with toast feedback
101
- - Uses `LAYOUT_AUTH_API` and `LAYOUT_AUTH_STATE` tokens (optional injection)
102
-
103
- #### AppCompanyBranchSelector
104
-
105
- Company and branch switcher in topbar. Shown when company feature is enabled.
106
-
107
- **Features:**
108
- - Button shows current company name and branch name
109
- - Popover with company/branch dropdowns
110
- - Auto-selects branch if only one available
111
- - Loading states and error handling
112
- - Uses `LAYOUT_AUTH_API` for data fetching and switching
113
- - Signal-based reactivity for button enable/disable state
114
-
115
- **User Workflow:**
116
- 1. Click company/branch button in topbar
117
- 2. Popover opens with company dropdown
118
- 3. Select company → Branches load
119
- 4. Select branch (required if branches exist)
120
- 5. Click "Switch" → Backend API call → JWT updated → Navigate to dashboard
121
-
122
- **Configuration requires:**
123
- 1. Auth service enabled in environment (`services.auth.enabled: true`)
124
- 2. Auth adapters provided in `app.config.ts`
125
-
126
- #### AppLauncher
16
+ ---
127
17
 
128
- App launcher grid in topbar for quick access to related applications.
18
+ ## 1. Set Up the Layout Route
129
19
 
130
- **Features:**
131
- - 3-column grid of app icons with names
132
- - External links (open in new tabs)
133
- - Icon support: PrimeNG, Material, or image URLs
134
- - Permission filtering via `permissionLogic`
135
- - Only visible when `layoutService.hasApps()` is true
20
+ Use `AppLayout` as the parent route component. All authenticated pages become children.
136
21
 
137
- **Configuration:**
138
22
  ```typescript
139
- import { ILauncherApp } from '@flusys/ng-layout';
23
+ // app.routes.ts
24
+ import { Routes } from '@angular/router';
25
+ import { AppLayout } from '@flusys/ng-layout';
140
26
 
141
- const apps: ILauncherApp[] = [
27
+ export const routes: Routes = [
142
28
  {
143
- id: 'docs',
144
- name: 'Docs',
145
- iconType: 1, // 1=primeng, 2=material, 3=image
146
- icon: 'pi pi-book',
147
- url: 'https://docs.example.com',
29
+ path: '',
30
+ component: AppLayout,
31
+ children: [
32
+ { path: 'dashboard', loadComponent: () => import('./pages/dashboard.component') },
33
+ { path: 'products', loadComponent: () => import('./pages/product-list.component') },
34
+ ],
148
35
  },
149
36
  {
150
- id: 'analytics',
151
- name: 'Analytics',
152
- iconType: 1,
153
- icon: 'pi pi-chart-bar',
154
- url: 'https://analytics.example.com',
155
- permissionLogic: { type: 'action', actionId: 'analytics.view' },
37
+ path: 'auth',
38
+ loadChildren: () => import('./pages/auth/auth.routes'),
156
39
  },
157
40
  ];
158
-
159
- // In app initialization:
160
- layoutService.setApps(apps);
161
41
  ```
162
42
 
163
- #### AppConfigurator
164
-
165
- Theme customizer dropdown. Opened from topbar via pStyleClass.
166
-
167
- **Features:**
168
- - Primary color selector (16 colors + noir)
169
- - Surface color selector (9 colors)
170
- - Preset selector (Aura, Lara, Nora)
171
- - Menu mode selector (static/overlay)
172
- - Dynamic theme application via PrimeUI themes API
173
-
174
- #### AppFloatingConfigurator
175
-
176
- Fixed-position floating button for theme customization. Provides quick access to dark mode toggle and color palette.
177
-
178
- ### 2. LayoutService
43
+ ---
179
44
 
180
- Signal-based service for managing layout state. Singleton (`providedIn: 'root'`).
45
+ ## 2. LayoutService — Reading and Updating Layout State
181
46
 
182
47
  ```typescript
183
48
  import { LayoutService } from '@flusys/ng-layout';
184
49
 
185
- @Component({...})
186
- export class AppComponent {
187
- private readonly layoutService = inject(LayoutService);
188
- }
189
- ```
50
+ @Component({ ... })
51
+ export class MyComponent {
52
+ private readonly layout = inject(LayoutService);
190
53
 
191
- **Signals:**
54
+ // Read signals
55
+ readonly isDark = this.layout.isDarkTheme; // Signal<boolean>
56
+ readonly isTopbar = this.layout.isTopbar; // Signal<boolean>
57
+ readonly isOverlay = this.layout.isOverlay; // Signal<boolean>
58
+ readonly menu = this.layout.menu; // Signal<IMenuItem[]> — permission-filtered
192
59
 
193
- | Signal | Type | Description |
194
- |--------|------|-------------|
195
- | `layoutConfig` | `Signal<LayoutConfig>` | Theme/preset/menuMode configuration |
196
- | `layoutState` | `Signal<LayoutState>` | UI state (menu active, sidebar visible) |
197
- | `transitionComplete` | `Signal<boolean>` | Dark mode transition state |
198
- | `userProfile` | `Signal<UserProfile \| null>` | Current user display data |
199
- | `companyProfile` | `Signal<CompanyProfile \| null>` | Current company display data |
200
- | `appName` | `Signal<string>` | App name for fallback display |
201
- | `menu` | `Computed<IMenuItem[]>` | Permission-filtered menu items |
202
- | `apps` | `Computed<ILauncherApp[]>` | Permission-filtered launcher apps |
203
-
204
- **Computed Signals:**
205
-
206
- | Signal | Type | Description |
207
- |--------|------|-------------|
208
- | `isDarkTheme` | `Computed<boolean>` | Whether dark theme is active |
209
- | `isSidebarActive` | `Computed<boolean>` | Whether sidebar/menu is visible |
210
- | `isOverlay` | `Computed<boolean>` | Whether menu mode is overlay |
211
- | `getPrimary` | `Computed<string>` | Current primary color |
212
- | `getSurface` | `Computed<string \| null>` | Current surface color |
213
- | `userName` | `Computed<string>` | User name or "User" fallback |
214
- | `userEmail` | `Computed<string>` | User email |
215
- | `userProfilePictureUrl` | `Computed<string \| null>` | Profile picture URL |
216
- | `companyName` | `Computed<string>` | Company name or appName fallback |
217
- | `companyLogoUrl` | `Computed<string \| null>` | Company logo URL |
218
- | `isAuthenticated` | `Computed<boolean>` | Whether user profile exists |
219
- | `hasApps` | `Computed<boolean>` | Whether filtered apps exist |
220
-
221
- **Methods:**
222
-
223
- | Method | Description |
224
- |--------|-------------|
225
- | `onMenuToggle()` | Toggle menu visibility (handles static/overlay/mobile) |
226
- | `onConfigUpdate()` | Emit config change event |
227
- | `onMenuStateChange(event)` | Emit menu item state change |
228
- | `reset()` | Reset menu state |
229
- | `setUserProfile(profile)` | Set user profile for layout display |
230
- | `setCompanyProfile(profile)` | Set company profile for layout display |
231
- | `setMenu(items)` | Set raw menu items (auto-filtered by permissions) |
232
- | `clearMenu()` | Clear menu items |
233
- | `setApps(apps)` | Set launcher apps (auto-filtered by permissions) |
234
- | `clearApps()` | Clear launcher apps |
235
- | `toggleDarkMode(config?)` | Toggle dark mode CSS class |
236
- | `isDesktop()` | Check if viewport > 991px |
237
- | `isMobile()` | Check if viewport <= 991px |
238
-
239
- **RxJS Observables:**
240
-
241
- | Observable | Description |
242
- |------------|-------------|
243
- | `menuSource$` | Menu state change events |
244
- | `resetSource$` | Menu reset events |
245
- | `configUpdate$` | Config change events |
246
- | `overlayOpen$` | Menu overlay opened |
247
-
248
- #### Configuration Persistence
249
-
250
- Layout configuration is automatically persisted to localStorage and restored on app bootstrap.
251
-
252
- **localStorage Key:** `flusys.layout.config`
253
-
254
- **Persisted Configuration (LayoutConfig):**
255
- ```typescript
256
- interface LayoutConfig {
257
- preset?: string; // "Aura" | "Lara" | "Nora"
258
- primary?: string; // "emerald" | "green" | "blue" | etc.
259
- surface?: string | null; // "slate" | "gray" | "zinc" | etc. | null
260
- darkTheme?: boolean;
261
- menuMode?: 'static' | 'overlay';
262
- }
263
- ```
264
-
265
- **Behavior:**
266
- - Changes saved automatically via Angular `effect()` when config changes
267
- - Configuration restored on page refresh (merged with defaults)
268
- - SSR-safe (`isPlatformBrowser` check)
269
- - Invalid preset falls back to "Aura", invalid menuMode falls back to "static"
270
- - Corrupted JSON is cleared and defaults are used
271
- - Version mismatches trigger automatic clearing
272
-
273
- **Clearing Saved Configuration:**
274
- ```typescript
275
- import { LayoutPersistenceService } from '@flusys/ng-layout';
276
-
277
- inject(LayoutPersistenceService).clear();
278
- ```
279
-
280
- ### 3. Theme Management
281
-
282
- Built-in theme support with light/dark modes using PrimeUI themes.
283
-
284
- **Dark mode toggle** uses the View Transition API (with fallback):
285
- ```typescript
286
- // AppTopbar toggles dark mode by updating layoutConfig signal:
287
- this.layoutService.layoutConfig.update((state) => ({
288
- ...state,
289
- darkTheme: !state.darkTheme,
290
- }));
291
- ```
292
-
293
- **Host binding** for root component:
294
- ```typescript
295
- @Component({
296
- host: { '[class.app-dark]': 'layoutService.isDarkTheme()' }
297
- })
298
- export class AppComponent {
299
- readonly layoutService = inject(LayoutService);
300
60
  }
301
61
  ```
302
62
 
303
- **Pre-defined Themes:**
304
-
305
- | Theme | Base | Primary Color |
306
- |-------|------|---------------|
307
- | `GreenTheme` | Material | `#01712c` |
308
- | `NavyBlueTheme` | Material | `#3535cd` |
309
-
310
- ```typescript
311
- import { GreenTheme, NavyBlueTheme } from '@flusys/ng-layout';
312
- ```
313
-
314
- ### 4. Auth Integration
315
-
316
- Layout components use injection tokens to access auth data without depending on ng-auth.
63
+ To push user/company profile into the topbar (done automatically by `ng-auth`'s bridge service):
317
64
 
318
- #### LAYOUT_AUTH_STATE Token
319
-
320
- Provides current user/company/branch state to layout components.
321
-
322
- ```typescript
323
- interface ILayoutAuthState {
324
- readonly currentCompanyInfo: Signal<ICompanyInfo | null>;
325
- readonly currentBranchInfo: Signal<IBranchInfo | null>;
326
- readonly loginUserData: Signal<IUserInfo | null>;
327
- }
328
- ```
329
-
330
- #### LAYOUT_AUTH_API Token
331
-
332
- Provides auth actions (logout, company switching) to layout components.
333
-
334
- ```typescript
335
- interface ILayoutAuthApi {
336
- logOut(): Observable<any>;
337
- navigateLogin(withUrl?: boolean): void;
338
- switchCompany(companyId: string, branchId: string): Observable<any>;
339
- getUserCompanies(): Observable<ICompanyInfo[]>;
340
- getCompanyBranches(companyId: string): Observable<IBranchInfo[]>;
341
- }
342
- ```
343
-
344
- #### Providing Auth Tokens
345
-
346
- ```typescript
347
- // app.config.ts
348
- import { LAYOUT_AUTH_STATE, LAYOUT_AUTH_API } from '@flusys/ng-layout';
349
- import { AuthLayoutStateAdapter, AuthLayoutApiAdapter } from '@flusys/ng-auth';
350
-
351
- providers: [
352
- { provide: LAYOUT_AUTH_STATE, useExisting: AuthLayoutStateAdapter },
353
- { provide: LAYOUT_AUTH_API, useExisting: AuthLayoutApiAdapter },
354
- ]
355
- ```
356
-
357
- Components inject tokens with `{ optional: true }` and degrade gracefully when auth is not provided.
358
-
359
- ### 5. Permission-Based Menu Filtering
360
-
361
- Menu items and launcher apps are automatically filtered based on user permissions using `permissionLogic`.
362
-
363
- **How it works:**
364
- 1. Raw menu items set via `layoutService.setMenu(items)`
365
- 2. `LayoutService.menu` is a `computed()` that filters via `filterMenuByPermissions()`
366
- 3. Permission evaluation uses `evaluateLogicNode()` from ng-shared
367
- 4. Same pattern applies to apps via `filterAppsByPermissions()`
368
-
369
- **ILogicNode Types:**
370
- ```typescript
371
- interface ILogicNode {
372
- id: string;
373
- type: 'group' | 'action' | 'role';
374
- operator?: 'AND' | 'OR'; // Required when type is 'group'
375
- actionId?: string; // Required when type is 'action'
376
- roleId?: string; // Required when type is 'role'
377
- children?: ILogicNode[]; // Required when type is 'group'
378
- }
379
- ```
380
-
381
- **Best Practice:** Use logic nodes (parent menu items without `routerLink`) with `permissionLogic` as permission gates for entire branches:
382
-
383
- ```typescript
384
- // Logic node gates all children
385
- {
386
- id: 'administration',
387
- label: 'Administration',
388
- icon: 'pi pi-cog',
389
- permissionLogic: { id: 'admin-check', type: 'action', actionId: 'admin.access' },
390
- children: [
391
- { id: 'users', label: 'Users', routerLink: ['/admin/users'] },
392
- { id: 'settings', label: 'Settings', routerLink: ['/admin/settings'] },
393
- ],
394
- }
395
- ```
396
-
397
- **Complex permission examples:**
398
- ```typescript
399
- // OR - user needs ANY permission
400
- permissionLogic: {
401
- id: 'reports-check',
402
- type: 'group',
403
- operator: 'OR',
404
- children: [
405
- { id: '1', type: 'action', actionId: 'reports.view' },
406
- { id: '2', type: 'role', roleId: 'manager-role-id' },
407
- ],
408
- }
409
-
410
- // AND - user needs ALL permissions
411
- permissionLogic: {
412
- id: 'admin-check',
413
- type: 'group',
414
- operator: 'AND',
415
- children: [
416
- { id: '1', type: 'action', actionId: 'admin.access' },
417
- { id: '2', type: 'role', roleId: 'superuser-role-id' },
418
- ],
419
- }
420
- ```
421
-
422
- ## Installation
423
-
424
- Build ng-layout after ng-core and ng-shared:
425
-
426
- ```bash
427
- npm run build:ng-core
428
- npm run build:ng-shared
429
- npm run build:ng-layout
430
- # Or build all libraries:
431
- npm run build:libs
432
- ```
433
-
434
- ## Usage Examples
435
-
436
- ### Basic Layout Setup
437
-
438
- ```typescript
439
- // app.component.ts
440
- import { Component, inject } from '@angular/core';
441
- import { RouterOutlet } from '@angular/router';
442
- import { AppLayout, LayoutService } from '@flusys/ng-layout';
443
-
444
- @Component({
445
- selector: 'app-root',
446
- standalone: true,
447
- imports: [RouterOutlet, AppLayout],
448
- template: `
449
- <app-layout>
450
- <router-outlet />
451
- </app-layout>
452
- `,
453
- host: { '[class.app-dark]': 'layoutService.isDarkTheme()' },
454
- })
455
- export class AppComponent {
456
- readonly layoutService = inject(LayoutService);
457
- }
458
- ```
459
-
460
- ### Menu Configuration
461
-
462
- ```typescript
463
- import { LayoutService, IMenuItem } from '@flusys/ng-layout';
464
-
465
- const menuItems: IMenuItem[] = [
466
- {
467
- label: 'Dashboard',
468
- icon: 'pi pi-home',
469
- routerLink: ['/dashboard'],
470
- },
471
- {
472
- label: 'Management',
473
- icon: 'pi pi-cog',
474
- children: [
475
- { label: 'Users', icon: 'pi pi-users', routerLink: ['/users'] },
476
- { label: 'Roles', icon: 'pi pi-shield', routerLink: ['/roles'] },
477
- ],
478
- },
479
- { separator: true },
480
- {
481
- label: 'Settings',
482
- icon: 'pi pi-cog',
483
- routerLink: ['/settings'],
484
- },
485
- ];
65
+ ---
486
66
 
487
- layoutService.setMenu(menuItems);
488
- ```
67
+ ## 3. Integration Tokens — Auth, Notifications, Language
489
68
 
490
- ### Auth Integration
69
+ Connect feature packages to the layout via injection tokens. Register them in `app.config.ts`.
491
70
 
492
71
  ```typescript
493
- // app.config.ts
494
- import { LAYOUT_AUTH_STATE, LAYOUT_AUTH_API } from '@flusys/ng-layout';
495
- import { AuthLayoutStateAdapter, AuthLayoutApiAdapter } from '@flusys/ng-auth';
72
+ import { provideAuthLayoutIntegration } from '@flusys/ng-auth';
73
+ import { provideNotificationProviders } from '@flusys/ng-notification';
74
+ import { provideLocalization } from '@flusys/ng-localization';
496
75
 
497
76
  export const appConfig: ApplicationConfig = {
498
77
  providers: [
499
- { provide: LAYOUT_AUTH_STATE, useExisting: AuthLayoutStateAdapter },
500
- { provide: LAYOUT_AUTH_API, useExisting: AuthLayoutApiAdapter },
78
+ ...provideAuthLayoutIntegration(), // topbar user profile + logout
79
+ ...provideNotificationProviders(), // topbar notification bell
80
+ ...provideLocalization({ ... }), // topbar language selector
501
81
  ],
502
82
  };
503
83
  ```
504
84
 
505
- ### Dynamic Menu from Backend
85
+ The layout reads these tokens to render topbar slots without directly importing feature packages.
506
86
 
507
- ```typescript
508
- import { LayoutService } from '@flusys/ng-layout';
509
- import { MenuApiService } from './services/menu-api.service';
510
-
511
- @Component({...})
512
- export class AppComponent implements OnInit {
513
- private readonly layoutService = inject(LayoutService);
514
- private readonly menuApi = inject(MenuApiService);
515
-
516
- async ngOnInit() {
517
- const response = await firstValueFrom(this.menuApi.getUserMenu());
518
- if (response.success) {
519
- this.layoutService.setMenu(response.data);
520
- }
521
- }
522
- }
523
- ```
524
-
525
- ## Best Practices
526
-
527
- ### Layout Structure
528
- - Use `AppLayout` as root layout component
529
- - Set menu items via `layoutService.setMenu()` during app initialization
530
- - Use `LayoutService` for all layout state changes
531
- - Don't manipulate DOM directly for layout changes
532
-
533
- ### Menu Management
534
- - Load menus dynamically from backend (IAM module)
535
- - Group related items under parent menu items with `permissionLogic`
536
- - Use PrimeIcons for consistency
537
- - Use `children` property for nested items (not `items`)
538
-
539
- ### Auth Integration
540
- - Use injection tokens (`LAYOUT_AUTH_STATE`, `LAYOUT_AUTH_API`)
541
- - Don't import ng-auth directly in ng-layout
542
- - Provide adapters at app level in `app.config.ts`
543
- - Layout works without auth (graceful degradation)
544
-
545
- ### Theme Management
546
- - Use CSS animations, not `@angular/animations`
547
- - Apply `app-dark` class to root element via host binding
548
- - Theme preferences persist automatically to localStorage
549
- - Test both light and dark themes for contrast
550
-
551
- ### Responsive Design
552
- - Use Tailwind for responsive utilities
553
- - Layout automatically handles responsive behavior (static → overlay on mobile)
554
- - Menu closes on navigation and outside clicks
555
-
556
- ## Common Issues
557
-
558
- ### Menu Not Showing
559
-
560
- Ensure menu items are set via `LayoutService.setMenu()`:
561
- ```typescript
562
- this.layoutService.setMenu([/* items */]);
563
- ```
87
+ ---
564
88
 
565
- ### Auth Info Not in Topbar
89
+ ## 4. Clear Persisted Layout
566
90
 
567
- Provide `LAYOUT_AUTH_STATE` in `app.config.ts`:
568
91
  ```typescript
569
- { provide: LAYOUT_AUTH_STATE, useExisting: AuthLayoutStateAdapter }
570
- ```
571
-
572
- ### Theme Not Applying
92
+ import { LayoutPersistenceService } from '@flusys/ng-layout';
573
93
 
574
- Add host binding to root component:
575
- ```typescript
576
- @Component({
577
- host: { '[class.app-dark]': 'layoutService.isDarkTheme()' }
578
- })
94
+ inject(LayoutPersistenceService).clear(); // removes flusys.layout.config from localStorage
579
95
  ```
580
96
 
581
- ### Sidebar Not Responsive
582
-
583
- Layout automatically handles responsive behavior. Ensure you're using the `AppLayout` component, not a custom layout.
584
-
585
- ## API Reference
586
-
587
- ### Components
588
-
589
- | Component | Selector | Description |
590
- |-----------|----------|-------------|
591
- | `AppLayout` | `app-layout` | Main layout wrapper |
592
- | `AppTopbar` | `app-topbar` | Application header |
593
- | `AppSidebar` | `app-sidebar` | Navigation sidebar |
594
- | `AppMenu` | `app-menu` | Menu container |
595
- | `AppMenuitem` | `[app-menuitem]` | Recursive menu item |
596
- | `AppFooter` | `app-footer` | Footer |
597
- | `AppProfile` | `app-profile` | User profile dropdown |
598
- | `AppCompanyBranchSelector` | `app-company-branch-selector` | Company/branch switcher |
599
- | `AppLauncher` | `app-launcher` | App launcher grid |
600
- | `AppConfigurator` | `app-configurator` | Theme customizer |
601
- | `AppFloatingConfigurator` | `app-floating-configurator` | Floating theme button |
602
-
603
- ### Services
604
-
605
- | Service | Description |
606
- |---------|-------------|
607
- | `LayoutService` | Signal-based layout state management |
608
- | `LayoutPersistenceService` | localStorage persistence with validation |
609
-
610
- ### Injection Tokens
611
-
612
- | Token | Interface | Description |
613
- |-------|-----------|-------------|
614
- | `LAYOUT_AUTH_STATE` | `ILayoutAuthState` | Auth state signals |
615
- | `LAYOUT_AUTH_API` | `ILayoutAuthApi` | Auth actions |
616
-
617
- ### Interfaces
618
-
619
- | Interface | Description |
620
- |-----------|-------------|
621
- | `IMenuItem` | Menu item configuration |
622
- | `ILauncherApp` | App launcher item configuration |
623
- | `ILayoutAuthState` | Auth state for layout |
624
- | `ILayoutAuthApi` | Auth actions for layout |
625
- | `ICompanyInfo` | Company information |
626
- | `IBranchInfo` | Branch information |
627
- | `IUserInfo` | User information |
628
- | `LayoutConfig` | Theme/preset configuration |
629
- | `LayoutState` | UI state (menu active, etc.) |
630
- | `UserProfile` | User display data |
631
- | `CompanyProfile` | Company display data |
632
- | `MenuChangeEvent` | Menu state change event |
633
-
634
- ### Utility Functions
635
-
636
- | Function | Description |
637
- |----------|-------------|
638
- | `filterMenuByPermissions(items, permissions)` | Filter menu items by permission logic |
639
- | `filterAppsByPermissions(apps, permissions)` | Filter launcher apps by permission logic |
640
-
641
- ### Pre-defined Themes
642
-
643
- | Export | Base Preset | Primary Color |
644
- |--------|-------------|---------------|
645
- | `GreenTheme` | Material | `#01712c` |
646
- | `NavyBlueTheme` | Material | `#3535cd` |
647
-
648
- ## See Also
649
-
650
- - **[CORE-GUIDE.md](./CORE-GUIDE.md)** - Configuration, interceptors
651
- - **[SHARED-GUIDE.md](./SHARED-GUIDE.md)** - Shared components, provider interfaces
652
- - **[AUTH-GUIDE.md](./AUTH-GUIDE.md)** - Authentication integration, adapters
653
-
654
97
  ---
655
98
 
656
- **Last Updated:** 2026-02-16
657
- **Angular Version:** 21
99
+ ## License
100
+
101
+ MIT © FLUSYS