@flusys/ng-layout
v4.1.1
Published
Layout components for FLUSYS Angular applications
Readme
@flusys/ng-layout
Application shell and layout system for the FLUSYS Angular platform — topbar, sidebar, menu, configurator, and layout state management.
Table of Contents
- Overview
- Features
- Compatibility
- Installation
- Quick Start
- Layout Configuration
- Injection Tokens
- LayoutService
- LayoutState
- Components
- Configuration Persistence
- Integration Tokens
- Troubleshooting
- License
Overview
@flusys/ng-layout provides the complete application shell for FLUSYS apps. It includes the topbar, sidebar, menu system, and layout configurator panel — all powered by Angular 21 signals and PrimeNG.
The layout integrates with auth, notification, and localization packages through injection token interfaces, maintaining clean package independence via the Provider Interface Pattern.
Features
- ✅ Three menu modes:
static,overlay,topbar - ✅ Signal-based layout state management (
LayoutService) - ✅ Layout persistence (theme, color, mode saved to localStorage)
- ✅ Company/branch selector in sidebar
- ✅ Topbar user profile dropdown with avatar
- ✅ Notification bell integration via injection token
- ✅ Language selector integration via injection token
- ✅ Responsive mobile layout
- ✅ Fully configurable color palettes and themes
- ✅ Zoneless-compatible
Compatibility
| Package | Version | |---------|---------| | Angular | 21+ | | @flusys/ng-core | 4.x | | @flusys/ng-shared | 4.x | | PrimeNG | 18+ | | Tailwind CSS | 3+ |
Installation
npm install @flusys/ng-layout @flusys/ng-core @flusys/ng-sharedQuick Start
1. Set Up App Layout Route
// app.routes.ts
import { Routes } from '@angular/router';
import { AppLayoutComponent } from '@flusys/ng-layout';
export const routes: Routes = [
{
path: '',
component: AppLayoutComponent,
children: [
{
path: 'dashboard',
loadComponent: () => import('./pages/dashboard/dashboard.component'),
},
{
path: 'products',
loadComponent: () => import('./pages/products/product-list.component'),
},
],
},
{
path: 'auth',
loadChildren: () => import('./pages/auth/auth.routes'),
},
];2. Define Menu Configuration
// app-menu.config.ts
import { IMenuItem } from '@flusys/ng-layout';
export const APP_MENU: IMenuItem[] = [
{
labelKey: 'menu.dashboard',
label: 'Dashboard',
icon: 'pi pi-home',
routerLink: ['/dashboard'],
},
{
labelKey: 'menu.products',
label: 'Products',
icon: 'pi pi-box',
items: [
{
labelKey: 'menu.products.list',
label: 'All Products',
routerLink: ['/products'],
},
{
labelKey: 'menu.products.create',
label: 'Add Product',
routerLink: ['/products/create'],
},
],
},
];3. Provide Layout Configuration
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { APP_CONFIG } from '@flusys/ng-core';
import { LAYOUT_MENU, LAYOUT_CONFIG } from '@flusys/ng-layout';
import { APP_MENU } from './app-menu.config';
import { environment } from './environments/environment';
export const appConfig: ApplicationConfig = {
providers: [
{ provide: APP_CONFIG, useValue: environment },
{ provide: LAYOUT_MENU, useValue: APP_MENU },
{
provide: LAYOUT_CONFIG,
useValue: {
menuMode: 'static',
theme: 'lara-light-blue',
colorScheme: 'light',
},
},
],
};Layout Configuration
LayoutConfig
interface LayoutConfig {
/** Menu display mode */
menuMode: 'static' | 'overlay' | 'topbar';
/** PrimeNG theme name */
theme: string;
/** Color scheme */
colorScheme: 'light' | 'dark' | 'dim';
/** Ripple effect */
ripple?: boolean;
/** Scale factor (12-16) */
scale?: number;
/** Menu theme */
menuTheme?: 'light' | 'dark' | 'colored';
/** Card border style */
inputStyle?: 'outlined' | 'filled';
}Menu Modes
Static Mode (Default)
Sidebar is always visible on desktop. Collapses to icons on tablet.
{ provide: LAYOUT_CONFIG, useValue: { menuMode: 'static' } }Overlay Mode
Sidebar slides over content. Click outside to close.
{ provide: LAYOUT_CONFIG, useValue: { menuMode: 'overlay' } }Topbar Mode (v4.0.1+)
Desktop renders horizontal navigation bar. Mobile falls back to vertical sidebar.
{ provide: LAYOUT_CONFIG, useValue: { menuMode: 'topbar' } }Submenu items appear on hover in topbar mode with automatic positioning.
Themes & Colors
Built-in themes (PrimeNG):
| Theme | Description |
|-------|-------------|
| lara-light-blue | Default — light blue |
| lara-dark-blue | Dark blue |
| lara-light-indigo | Light indigo |
| lara-dark-indigo | Dark indigo |
| lara-light-purple | Light purple |
| lara-dark-purple | Dark purple |
| lara-light-teal | Light teal |
| lara-dark-teal | Dark teal |
Injection Tokens
| Token | Type | Description |
|-------|------|-------------|
| LAYOUT_CONFIG | InjectionToken<LayoutConfig> | Initial layout configuration |
| LAYOUT_MENU | InjectionToken<IMenuItem[]> | Application menu items |
| LAYOUT_AUTH_STATE | InjectionToken<ILayoutAuthState> | Auth state bridge (from ng-auth) |
| LAYOUT_AUTH_API | InjectionToken<ILayoutAuthApi> | Auth API bridge (from ng-auth) |
| LAYOUT_NOTIFICATION_BELL | InjectionToken<INotificationBellProvider> | Notification bell (from ng-notification) |
| LAYOUT_LANGUAGE_SELECTOR | InjectionToken<ILanguageSelectorProvider> | Language selector (from ng-localization) |
LayoutService
Central signal-based service for layout state management.
import { LayoutService } from '@flusys/ng-layout';
@Component({ ... })
export class MyComponent {
private layoutService = inject(LayoutService);
// Computed signals (read-only)
isStatic = this.layoutService.isStatic(); // boolean
isOverlay = this.layoutService.isOverlay(); // boolean
isTopbar = this.layoutService.isTopbar(); // boolean
isMobile = this.layoutService.isMobile(); // boolean
isMenuOpen = this.layoutService.isMenuOpen(); // boolean
// Actions
toggleMenu(): void {
this.layoutService.toggleMenu();
}
setTheme(theme: string): void {
this.layoutService.setTheme(theme);
}
setMenuMode(mode: 'static' | 'overlay' | 'topbar'): void {
this.layoutService.setMenuMode(mode);
}
}LayoutService API:
| Member | Type | Description |
|--------|------|-------------|
| config | Signal<LayoutConfig> | Current layout configuration |
| state | Signal<LayoutState> | Current layout state |
| isStatic() | Signal<boolean> | True if menu mode is static |
| isOverlay() | Signal<boolean> | True if menu mode is overlay |
| isTopbar() | Signal<boolean> | True if menu mode is topbar |
| isMobile() | Signal<boolean> | True on mobile viewport |
| isMenuOpen() | Signal<boolean> | True if sidebar is open |
| toggleMenu() | void | Toggle sidebar open/close |
| hideMenu() | void | Force sidebar closed |
| setTheme(theme) | void | Change PrimeNG theme |
| setMenuMode(mode) | void | Change menu mode |
| setColorScheme(scheme) | void | Change color scheme |
LayoutState
Reactive state object managed by LayoutService:
interface LayoutState {
/** Sidebar open on mobile */
staticMenuMobileActive: boolean;
/** Overlay sidebar open */
overlayMenuActive: boolean;
/** Desktop sidebar collapsed */
staticMenuDesktopInactive: boolean;
/** Right-click menu visible */
menuHoverActive: boolean;
/** Config panel open */
configSidebarVisible: boolean;
/** Topbar nav visible (topbar mode) */
topbarMenuVisible: boolean;
}Components
AppLayoutComponent
Root layout component. Use this as the parent route component.
import { AppLayoutComponent } from '@flusys/ng-layout';
// In routes:
{ path: '', component: AppLayoutComponent, children: [...] }Renders:
AppTopbarComponent(header)AppSidebarComponent(left navigation)<router-outlet>(page content)AppConfiguratorComponent(floating settings panel)
AppTopbarComponent
Application header bar with:
- Logo / app name
- Menu toggle button (mobile)
- User profile dropdown (avatar, name, logout)
- Sign-up link (conditionally shown based on
isSignUpEnabled()) - Notification bell slot (via
LAYOUT_NOTIFICATION_BELLtoken) - Language selector slot (via
LAYOUT_LANGUAGE_SELECTORtoken)
AppSidebarComponent
Left navigation panel containing:
AppMenuComponent(navigation items)AppCompanyBranchSelectorComponent(if company selection enabled)
AppMenuComponent
Renders the menu tree from LAYOUT_MENU token. Supports:
- Nested submenus (unlimited depth)
- Active route highlighting
- Translation keys via
labelKey - Icons via PrimeIcons
AppMenuitemComponent
Individual menu item component. Handles:
- Route navigation
- Submenu expand/collapse
- Topbar hover positioning
routerLinkActiveOptions
AppCompanyBranchSelectorComponent
Dropdown selectors for company and branch. Shown in sidebar when services.auth.features.companySelection is enabled.
AppConfiguratorComponent
Floating right-side panel for live layout customization:
- Theme picker
- Color scheme toggle (light/dark/dim)
- Menu mode selector (static/overlay/topbar)
- Scale slider
Configuration Persistence
LayoutPersistenceService automatically saves and restores layout preferences to localStorage:
// Automatically persisted keys:
// - flusys.layout.theme
// - flusys.layout.colorScheme
// - flusys.layout.menuMode
// - flusys.layout.scale
// - flusys.layout.rippleNo manual setup required — persistence is active whenever LayoutService is injected. To clear persisted settings:
import { LayoutPersistenceService } from '@flusys/ng-layout';
this.persistenceService.clear();Integration Tokens
Auth Integration (from ng-auth)
import { provideAuthLayoutIntegration } from '@flusys/ng-auth';
// app.config.ts providers:
...provideAuthLayoutIntegration()
// Provides: LAYOUT_AUTH_STATE, LAYOUT_AUTH_APILAYOUT_AUTH_STATE interface:
interface ILayoutAuthState {
user: Signal<ICurrentUser | null>;
company: Signal<ICompany | null>;
branch: Signal<IBranch | null>;
isAuthenticated: Signal<boolean>;
profilePictureUrl: Signal<string | null>;
companyLogoUrl: Signal<string | null>;
}LAYOUT_AUTH_API interface:
interface ILayoutAuthApi {
logout(): Observable<void>;
selectCompany(companyId: string, branchId: string): Observable<void>;
}Notification Bell Integration (from ng-notification)
import { provideNotificationProviders } from '@flusys/ng-notification';
...provideNotificationProviders()
// Provides: LAYOUT_NOTIFICATION_BELLLanguage Selector Integration (from ng-localization)
import { provideLocalization } from '@flusys/ng-localization';
...provideLocalization()
// Provides: LAYOUT_LANGUAGE_SELECTORTroubleshooting
Sidebar doesn't open on mobile
Ensure AppLayoutComponent is the parent route component, not just imported as a standalone component in a non-route context.
Menu items don't highlight active route
Add routerLinkActiveOptions: { exact: true } to leaf menu items and { exact: false } to parent items:
{
labelKey: 'menu.dashboard',
routerLink: ['/dashboard'],
routerLinkActiveOptions: { exact: true },
}Topbar submenus appear behind other elements
Set a higher z-index on .topbar-submenu in your global styles, or ensure no parent has overflow: hidden.
Theme not changing
Check that LayoutPersistenceService is provided (it's automatic when LayoutService is used). If the theme is cached, call persistenceService.clear() once.
No provider for LAYOUT_AUTH_STATE
You must call provideAuthLayoutIntegration() in app.config.ts after enabling ng-auth.
License
MIT © FLUSYS
