@lerian/console-layout
v1.0.0-beta.5
Published
Reusable layout components for Midaz console and plugins
Maintainers
Readme
@midaz/console-layout
Reusable layout components for Midaz console and plugins, providing a complete Header and Sidebar system with API integration.
Features
✅ Complete Header System
- LedgerSelector with search and filtering
- UserDropdown with profile and logout
- SettingsDropdown with customizable actions
✅ Complete Sidebar System
- Responsive collapse/expand behavior
- OrganizationSwitcher integration
- Configurable navigation items
- Plugin support with custom rendering
- Animated transitions and tooltips
✅ API Integration
- Configurable fetcher with authentication
- Organizations, Ledgers, and Plugin menu clients
- React Query integration for caching
- Auto-selection of organizations and ledgers
✅ Complete Layout Integration
- ConsoleLayout with full configuration
- SimpleConsoleLayout for quick setup
- useConsoleLayout hook for routing and state
- Auto-configuration of API and QueryClient
✅ State Management
- OrganizationProvider for org/ledger state
- SidebarProvider for collapse state
- TypeScript support with full type safety
Installation
npm install @midaz/console-layoutPeer Dependencies
npm install react react-dom next next-auth @tanstack/react-queryQuick Start
1. Simple Usage (Perfect for Plugins)
import { ConsoleLayout } from "@midaz/console-layout";
import "@midaz/console-layout/styles";
function MyPlugin() {
return (
<ConsoleLayout>
<h1>My Plugin Content</h1>
</ConsoleLayout>
);
}2. Advanced Usage (Full Control)
import { ConsoleLayout, useConsoleLayout } from "@midaz/console-layout";
import { Home, Settings } from "lucide-react";
function MyApp() {
return (
<ConsoleLayout
config={{
baseUrl: "http://localhost:3000",
defaultSidebarCollapsed: false,
}}
headerProps={{
version: "1.0.0",
userDropdownProps: {
userName: "John Doe",
onLogout: () => signOut(),
},
}}
sidebarProps={{
mainItems: [
{ id: "home", title: "Home", icon: <Home />, href: "/" },
{
id: "settings",
title: "Settings",
icon: <Settings />,
href: "/settings",
},
],
}}
>
<MyContent />
</ConsoleLayout>
);
}3. Using the Layout Hook
import { useConsoleLayout } from "@midaz/console-layout";
function MyComponent() {
const { navigate, isActive, organization, sidebar } = useConsoleLayout();
return (
<div>
<button onClick={() => navigate("/assets")}>Go to Assets</button>
<button onClick={sidebar.toggle}>Toggle Sidebar</button>
<p>Current org: {organization.current?.legalName}</p>
</div>
);
}4. Manual Setup (Individual Components)
import {
Header,
Sidebar,
OrganizationProvider,
SidebarProvider,
OrganizationSwitcher,
} from "@midaz/console-layout";
import { Home, DollarSign, Coins } from "lucide-react";
function App() {
return (
<OrganizationProvider>
<SidebarProvider>
<div className="flex h-screen">
<Sidebar
headerContent={<OrganizationSwitcher />}
mainItems={[
{ id: "home", title: "Home", icon: <Home />, href: "/" },
]}
ledgerItems={[
{
id: "assets",
title: "Assets",
icon: <DollarSign />,
href: "/assets",
},
{
id: "accounts",
title: "Accounts",
icon: <Coins />,
href: "/accounts",
},
]}
/>
<div className="flex-1 flex flex-col">
<Header
version="1.0.0"
userDropdownProps={{
userName: "John Doe",
onLogout: () => signOut(),
}}
/>
<main className="flex-1 p-6">{/* Your content */}</main>
</div>
</div>
</SidebarProvider>
</OrganizationProvider>
);
}Component API
ConsoleLayout
Main layout component with full configuration options.
interface ConsoleLayoutProps {
config: ConsoleLayoutConfig;
headerProps?: Omit<HeaderProps, "children">;
sidebarProps?: Omit<SidebarProps, "headerContent">;
organizationSwitcher?: React.ReactNode;
children: React.ReactNode;
className?: string;
showSidebar?: boolean;
showHeader?: boolean;
}
interface ConsoleLayoutConfig {
baseUrl: string;
defaultSidebarCollapsed?: boolean;
useExistingQueryClient?: boolean;
queryClient?: QueryClient;
}SimpleConsoleLayout
Simplified layout with sensible defaults.
interface SimpleConsoleLayoutProps {
baseUrl: string;
version?: string;
userName?: string;
additionalMainItems?: SidebarMenuItemConfig[];
additionalLedgerItems?: SidebarMenuItemConfig[];
onLogout?: () => void;
onSettings?: {
onOrganizationsClick?: () => void;
onUsersClick?: () => void;
// ... more callbacks
};
children: React.ReactNode;
text?: {
/* internationalization overrides */
};
}useConsoleLayout Hook
Hook for routing and state management.
interface UseConsoleLayoutReturn {
pathname: string;
navigate: (href: string) => void;
isActive: (href: string) => boolean;
organization: {
current: OrganizationDto;
setOrganization: (org: OrganizationDto) => void;
currentLedger: LedgerDto;
setLedger: (ledger: LedgerDto) => void;
};
sidebar: {
isCollapsed: boolean;
toggle: () => void;
setCollapsed: (collapsed: boolean) => void;
};
createNavItem: (config: SidebarMenuItemConfig) => SidebarMenuItemConfig;
}Sidebar
Complete sidebar with navigation, organization switcher, and plugin support.
interface SidebarProps {
/** Header content - usually OrganizationSwitcher */
headerContent?: React.ReactNode;
/** Main navigation items */
mainItems?: SidebarMenuItemConfig[];
/** Ledger-specific items that require a selected ledger */
ledgerItems?: SidebarMenuItemConfig[];
/** Whether to show plugins section */
showPlugins?: boolean;
/** Custom plugin renderer */
renderPlugin?: (plugin: PluginManifestDto) => React.ReactNode | null;
/** Text for sections */
text?: {
ledgerSectionTitle?: string;
pluginsSectionTitle?: string;
noLedgerDisabledReason?: string;
};
/** Whether to show mobile expand button */
showExpandButton?: boolean;
/** Check if item is active based on pathname */
isActiveItem?: (href: string, pathname: string) => boolean;
}
interface SidebarMenuItemConfig {
id: string;
title: string;
icon: React.ReactNode;
href: string;
disabled?: boolean;
disabledReason?: string;
}Header
Complete header with ledger selector, user dropdown, and settings.
interface HeaderProps {
version?: string;
locale?: string;
showLedgerSelector?: boolean;
userDropdownProps?: UserDropdownProps;
settingsDropdownProps?: SettingsDropdownProps;
}OrganizationSwitcher
Organization switcher for sidebar header.
interface OrganizationSwitcherProps {
logoAlt?: string;
defaultLogo?: React.ReactNode;
renderOrganizationItem?: (
organization: OrganizationDto,
isSelected: boolean,
onSelect: () => void
) => React.ReactNode;
}UserDropdown
interface UserDropdownProps {
userName?: string;
isAuthEnabled?: boolean;
docsUrl?: string;
onLogout?: () => void;
onDocsClick?: () => void;
text?: {
user?: string;
documentation?: string;
logout?: string;
};
}SettingsDropdown
interface SettingsDropdownProps {
items?: SettingsDropdownItem[];
onOrganizationsClick?: () => void;
onUsersClick?: () => void;
onApplicationsClick?: () => void;
onSystemClick?: () => void;
onAboutClick?: () => void;
text?: {
settings?: string;
organizations?: string;
users?: string;
applications?: string;
system?: string;
about?: string;
};
permissions?: {
canViewUsers?: boolean;
canViewApplications?: boolean;
};
}Advanced Usage
Custom Sidebar Items
const customLedgerItems: SidebarMenuItemConfig[] = [
{
id: 'assets',
title: 'Assets',
icon: <DollarSign />,
href: '/assets',
disabled: !hasLedger,
disabledReason: 'Select a ledger first'
}
]
<Sidebar ledgerItems={customLedgerItems} />Custom Plugin Rendering
<Sidebar
renderPlugin={(plugin) => (
<SidebarItem
key={plugin.name}
title={plugin.title}
icon={<CustomIcon name={plugin.icon} />}
href={`/plugins${plugin.route}`}
/>
)}
/>Custom Active Item Logic
<Sidebar
isActiveItem={(href, pathname) => {
// Custom logic for determining active state
return pathname.startsWith(href);
}}
/>Internationalization
<Sidebar
text={{
ledgerSectionTitle: intl.formatMessage({ id: 'sidebar.ledger' }),
pluginsSectionTitle: intl.formatMessage({ id: 'sidebar.plugins' }),
noLedgerDisabledReason: intl.formatMessage({ id: 'sidebar.no.ledger' })
}}
/>
<Header
userDropdownProps={{
text: {
user: intl.formatMessage({ id: 'user' }),
documentation: intl.formatMessage({ id: 'documentation' }),
logout: intl.formatMessage({ id: 'logout' })
}
}}
/>Styling
The library includes pre-built Tailwind CSS styles. Import the CSS:
import "@midaz/console-layout/styles";Or use your own CSS variables:
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
/* ... more variables */
}TypeScript
The library is fully typed. Import types as needed:
import {
OrganizationDto,
LedgerDto,
PluginManifestDto,
SidebarMenuItemConfig,
} from "@midaz/console-layout";Build Output
- ESM: 28.21 KB (optimized for modern bundlers)
- CJS: 36.77 KB (Node.js compatibility)
- CSS: 16.19 KB (Tailwind styles)
- Types: 19.57 KB (Full TypeScript definitions)
Development
# Install dependencies
npm install
# Build the library
npm run build
# Test with the demo app
cd test-app && npm run devLicense
MIT
