@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 +51 -607
- package/assets/layout/_core.scss +19 -0
- package/assets/layout/_footer.scss +18 -1
- package/assets/layout/_forms.scss +12 -32
- package/assets/layout/_menu.scss +5 -5
- package/assets/layout/_responsive.scss +18 -0
- package/assets/layout/_rtl.scss +482 -0
- package/assets/layout/_topbar.scss +177 -124
- package/assets/layout/_topbar_nav.scss +345 -0
- package/assets/layout/_typography.scss +25 -30
- package/assets/layout/_utils.scss +12 -16
- package/assets/layout/layout.scss +3 -1
- package/assets/layout/variables/_common.scss +17 -17
- package/assets/layout/variables/_dark.scss +3 -3
- package/assets/layout/variables/_light.scss +3 -3
- package/assets/style.scss +3 -3
- package/fesm2022/flusys-ng-layout.mjs +1784 -1344
- package/fesm2022/flusys-ng-layout.mjs.map +1 -1
- package/package.json +10 -11
- package/types/flusys-ng-layout.d.ts +229 -256
package/README.md
CHANGED
|
@@ -1,657 +1,101 @@
|
|
|
1
|
-
# @flusys/ng-layout
|
|
1
|
+
# @flusys/ng-layout
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Application shell for the FLUSYS Angular platform — topbar, sidebar, menu, and signal-based layout state management.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@flusys/ng-layout)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
7
|
|
|
7
|
-
|
|
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
|
-
|
|
25
|
-
import { AppLayout } from '@flusys/ng-layout';
|
|
10
|
+
## Installation
|
|
26
11
|
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
18
|
+
## 1. Set Up the Layout Route
|
|
129
19
|
|
|
130
|
-
|
|
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
|
-
|
|
23
|
+
// app.routes.ts
|
|
24
|
+
import { Routes } from '@angular/router';
|
|
25
|
+
import { AppLayout } from '@flusys/ng-layout';
|
|
140
26
|
|
|
141
|
-
const
|
|
27
|
+
export const routes: Routes = [
|
|
142
28
|
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
|
|
151
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
187
|
-
private readonly
|
|
188
|
-
}
|
|
189
|
-
```
|
|
50
|
+
@Component({ ... })
|
|
51
|
+
export class MyComponent {
|
|
52
|
+
private readonly layout = inject(LayoutService);
|
|
190
53
|
|
|
191
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
488
|
-
```
|
|
67
|
+
## 3. Integration Tokens — Auth, Notifications, Language
|
|
489
68
|
|
|
490
|
-
|
|
69
|
+
Connect feature packages to the layout via injection tokens. Register them in `app.config.ts`.
|
|
491
70
|
|
|
492
71
|
```typescript
|
|
493
|
-
|
|
494
|
-
import {
|
|
495
|
-
import {
|
|
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
|
-
|
|
500
|
-
|
|
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
|
-
|
|
85
|
+
The layout reads these tokens to render topbar slots without directly importing feature packages.
|
|
506
86
|
|
|
507
|
-
|
|
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
|
-
|
|
89
|
+
## 4. Clear Persisted Layout
|
|
566
90
|
|
|
567
|
-
Provide `LAYOUT_AUTH_STATE` in `app.config.ts`:
|
|
568
91
|
```typescript
|
|
569
|
-
{
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
### Theme Not Applying
|
|
92
|
+
import { LayoutPersistenceService } from '@flusys/ng-layout';
|
|
573
93
|
|
|
574
|
-
|
|
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
|
-
|
|
657
|
-
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT © FLUSYS
|