@taruvi/navkit
v0.0.10
Published
A modern, responsive, and highly performant navigation bar component library for the Taruvi ecosystem. Built with React 19, TypeScript, and Material-UI with automatic optimizations via React Compiler.
Readme
Taruvi Navkit
A modern, responsive, and highly performant navigation bar component library for the Taruvi ecosystem. Built with React 19, TypeScript, and Material-UI with automatic optimizations via React Compiler.
Features
Core Components
- App Launcher: Grid-based application launcher with real-time search and filtering
- Smart Shortcuts: Quick access shortcuts with responsive desktop/mobile views and hamburger menu on mobile
- User Profile: Avatar-based profile menu with preferences access and logout functionality
- Mattermost Chat Integration: Embedded chat modal with JWT authentication and external link option
- Click-Outside Detection: Intelligent menu closing with mutually exclusive dropdown behavior
Technical Highlights
- Responsive Design: Mobile-first approach with strategic breakpoints (900px for desktop)
- Smart Navigation: Context-aware navigation system (desk mode vs external mode)
- Type-Safe: Full TypeScript support with strict mode enabled
- Optimized Performance: React Compiler with automatic memoization + manual optimizations
- Modern React: Leverages React 19 features (startTransition, concurrent rendering)
- Design System: Centralized design tokens for consistent theming
- Accessibility: MUI components with built-in ARIA attributes and keyboard navigation
Quick Start
Installation
# Clone or add as dependency
npm install @taruvi/navkit
# Install peer dependencies
npm install @mui/material @emotion/react @emotion/styled
npm install @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/free-regular-svg-icons @fortawesome/react-fontawesomeBasic Setup
import Navkit from '@taruvi/navkit'
import { TaruviClient } from '@taruvi-io/sdk'
function App() {
const client = new TaruviClient({
apiUrl: 'https://api.taruvi.io',
// ... other config
})
return <Navkit client={client} />
}
export default AppDevelopment
Development Scripts
# Start development server with HMR (Hot Module Replacement)
npm run dev
# Build for production (TypeScript check + Vite build)
npm run build
# Preview production build locally
npm run preview
# Run ESLint for code quality
npm run lint
# Test Mattermost integration in isolation
npm run test:mattermostDevelopment Workflow
- Make changes to source files in
src/ - See updates instantly with Vite's Fast Refresh (HMR)
- Type-check automatically via TypeScript in your IDE
- Lint before commit with
npm run lint - Build before deploy with
npm run build
Usage
Integration Patterns
Standalone App Integration
import Navkit from '@taruvi/navkit'
import { TaruviClient } from '@taruvi-io/sdk'
function App() {
const client = new TaruviClient({
apiUrl: process.env.VITE_API_URL,
tenantId: process.env.VITE_TENANT_ID,
})
return (
<>
<Navkit client={client} />
<main>{/* Your app content */}</main>
</>
)
}Taruvi Desk Integration
import Navkit from '@taruvi/navkit'
import { useDesk } from '@taruvi-io/desk-sdk'
function DeskApp() {
const { client } = useDesk()
return <Navkit client={client} />
}Client Object Requirements
The client prop expects an object compatible with @taruvi-io/sdk that provides:
User class for user data and apps
getApps(): Fetch available applicationsgetData(): Fetch user profile data (fullName, pfp, username, email)
Settings class for site configuration
get(): Fetch site settings (logo, frontendUrl, mattermostUrl, shortcuts)
Auth class for authentication
isUserAuthenticated(): Check authentication status- JWT token management (future)
Architecture
Component Structure
Navkit (App.tsx)
├── NavkitProvider (NavkitContext) - React Context for global state
│ ├── State: appsList, userData, isUserAuthenticated, jwtToken, isDesk
│ ├── Refs: siteSettings, user, settings (SDK instances)
│ └── Functions: navigateToUrl, getData, authenticateUser
├── NavkitContent - Main UI component
├── AppLauncher - App grid with search
├── Profile - User avatar and name
│ └── ProfileMenu - Preferences and logout
├── Shortcuts - Quick action icons
│ └── ShortcutsMenu - Mobile dropdown
└── MattermostChat - Chat modalState Management
Navkit uses React Context API for centralized state management:
- NavigationContext - Centralized provider for all app state and navigation logic
- useNavigation hook - Custom hook for consuming context in child components
- Separate state variables for granular updates (reduces unnecessary re-renders)
- useRef for SDK instances and siteSettings to prevent re-renders
- startTransition for batching multiple state updates on initial load (6+ renders → 1 render)
- BroadcastChannel for cross-tab synchronization (refreshes on profile updates)
- React Compiler for automatic memoization and optimization
Performance Optimizations
- Initial render count reduced from 6+ to 1 via
startTransition - SDK instances and siteSettings in refs prevent re-renders
- Separate state variables allow granular component updates
- React Compiler automatically memoizes components and callbacks
- BroadcastChannel enables real-time updates across tabs
Navigation Modes
Navkit intelligently handles navigation based on context:
1. Desk Mode (when frontendUrl is set)
- When: Running inside Taruvi Desk application
- Behavior: Relative navigation within the app
- Examples:
https://app.taruvi.io/mail→ navigates to/mail/preferences→ navigates to/preferences
- Detection: Checks if
window.location.hrefincludesfrontendUrl
// Site settings with frontendUrl
{
frontendUrl: 'https://desk.taruvi.io',
// ... other settings
}2. External Mode (no frontendUrl)
- When: Running in standalone app or
frontendUrlnot set - Behavior: Opens URLs in new tab
- Examples:
https://mail.taruvi.io→ opens in new tabhttps://external-app.com→ opens in new tab
- Purpose: Prevents navigating away from host application
// Site settings without frontendUrl
{
frontendUrl: '', // or null/undefined
// ... other settings
}Navigation Hook
import { useNavigation } from './NavkitContext'
// In any child component
function MyComponent() {
const { navigateToUrl, isDesk, siteSettings } = useNavigation()
// Automatically detects mode and navigates appropriately
navigateToUrl('/app-name')
}Responsive Breakpoints
Navkit uses a mobile-first responsive design strategy:
Mobile (xs): < 900px
- User name: Hidden (avatar only)
- Shortcuts: Hamburger menu dropdown
- App launcher: Full-width (95vw)
- Touch targets: Minimum 44x44px
- Optimizations: Reduced clutter for small screens
Desktop (md+): ≥ 900px
- User name: Visible next to avatar
- Shortcuts: Inline horizontal layout
- App launcher: Fixed width (600px)
- Enhanced UX: More information density
Implementation Example
// Conditional rendering based on breakpoint
<Typography sx={{ display: { xs: 'none', md: 'block' } }}>
{userData.fullName}
</Typography>
// Responsive dimensions
container: {
width: { xs: '95vw', sm: '80vw', md: '70vw', lg: '600px' },
height: { xs: '90vh', md: '80vh' },
}Testing Breakpoints
Test the following widths for complete coverage:
- 320px: Minimum mobile (iPhone SE)
- 768px: Tablet
- 900px: Breakpoint threshold
- 1024px: Small desktop
- 1920px: Large desktop
Configuration
Site Settings
The component expects the following settings from the SDK:
interface SiteSettings {
logo: string // Navigation bar logo URL
frontendUrl: string // Base URL for desk mode navigation (optional)
mattermostUrl: string // Mattermost server URL (optional)
shortcuts: AppData[] // Quick action shortcuts
}
// Example
{
logo: 'https://cdn.taruvi.io/logo.png',
frontendUrl: 'https://desk.taruvi.io',
mattermostUrl: 'https://chat.taruvi.io',
shortcuts: [
{
id: '1',
appname: 'Mail',
icon: 'envelope',
url: '/mail'
},
{
id: '2',
appname: 'Calendar',
icon: 'calendar',
url: '/calendar'
},
{
id: '3',
appname: 'Chat',
icon: 'comments',
url: '#' // Special handling for chat
}
]
}User Data
interface UserData {
fullName: string // Full display name
pfp: string // Profile picture URL
username: string // Username or handle
email: string // User email address
}
// Example
{
fullName: 'John Doe',
pfp: 'https://cdn.taruvi.io/avatars/johndoe.jpg',
username: 'johndoe',
email: '[email protected]'
}App Data
interface AppData {
id: string // Unique app identifier
appname: string // Display name
icon: string // FontAwesome icon name (without 'fa-' prefix)
url: string // App URL or path
}
// Example
{
id: 'app-mail-001',
appname: 'Mail',
icon: 'envelope', // Renders as fa-envelope
url: 'https://mail.taruvi.io'
}FontAwesome Icon Names
Icons use FontAwesome Free icon names without the fa- prefix:
envelope→fa-envelopecalendar→fa-calendarhome→fa-homecog→fa-cog
See FontAwesome Free Icons for available icons.
Styling
Design System
Navkit uses a centralized design system with design tokens in src/styles/variables.ts:
Color Palette
colours = {
text: {
primary: '#333333', // Main text
secondary: '#424242', // Secondary text
tertiary: '#9e9e9e', // Disabled/subtle text
},
bg: {
white: '#fff', // White background
light: '#f5f5f5', // Light grey background
avatar: '#E0E0E0', // Avatar placeholder
},
border: {
light: '#e0e0e0', // Border color
},
}Spacing Scale
spacing = {
xs: '10px', // Extra small
sm: 1.5, // Small (12px with MUI 8px base)
md: 2, // Medium (16px)
lg: 3, // Large (24px)
}Typography
typography = {
sizes: {
xs: '0.8125rem', // 13px
sm: '0.875rem', // 14px
md: '1.125rem', // 18px
},
weights: {
regular: 400,
semibold: 600,
},
}Dimensions
dimensions = {
navHeight: '60px',
avatarSize: 40,
iconSize: {
sm: '18px',
md: '24px',
lg: '1.25rem',
},
}Customization Options
1. Component-Specific Styles
Each component has a .styles.ts file:
// Profile.styles.ts
import { colours, spacing, typography } from '../../styles/variables'
export const profileStyles = {
userName: {
fontSize: typography.sizes.sm,
color: colours.text.primary,
padding: spacing.xs,
}
}2. Design Tokens
Modify src/styles/variables.ts for global changes:
// Change primary text color globally
export const colours = {
text: {
primary: '#000000', // Darker text
// ...
}
}3. MUI Theme Provider
Wrap Navkit with MUI ThemeProvider for advanced theming:
import { createTheme, ThemeProvider } from '@mui/material/styles'
const theme = createTheme({
palette: {
primary: {
main: '#1976d2',
},
},
})
function App() {
return (
<ThemeProvider theme={theme}>
<Navkit client={client} />
</ThemeProvider>
)
}Tech Stack
Core Dependencies
| Package | Version | Purpose | |---------|---------|---------| | React | 19.1.1 | UI framework with concurrent features | | React DOM | 19.1.1 | DOM rendering | | TypeScript | ~5.9.3 | Type safety and developer experience |
Peer Dependencies
| Package | Version | Purpose | |---------|---------|---------| | @mui/material | ^5.0.0 | UI component library | | @emotion/react | ^11.0.0 | CSS-in-JS (MUI dependency) | | @emotion/styled | ^11.0.0 | Styled components (MUI dependency) | | @fortawesome/fontawesome-svg-core | ^6.0.0 | Icon library core | | @fortawesome/free-solid-svg-icons | ^6.0.0 | Solid icons | | @fortawesome/free-regular-svg-icons | ^6.0.0 | Regular icons | | @fortawesome/react-fontawesome | ^0.2.0 | React icon components | | @taruvi-io/sdk | latest | Taruvi SDK for API integration |
Development Dependencies
| Package | Version | Purpose | |---------|---------|---------| | Vite | 7.1.7 | Build tool and dev server | | @vitejs/plugin-react | ^5.0.4 | Vite React plugin | | babel-plugin-react-compiler | ^19.1.0-rc.3 | Automatic optimizations | | ESLint | ^9.36.0 | Code linting | | typescript-eslint | ^8.45.0 | TypeScript ESLint support |
Why These Choices?
- React 19: Latest features (startTransition, concurrent rendering)
- Vite: Fast HMR (< 100ms), optimized builds
- MUI: Accessible, responsive, well-maintained
- TypeScript: Catch errors at compile time
- React Compiler: Automatic performance optimizations
Performance Optimizations
Automatic Optimizations
React Compiler
- Automatic memoization of components and values
- Callback stabilization without manual
useCallback - Reduced re-renders through intelligent optimization
- No boilerplate (no manual
useMemo,React.memo)
Vite Build Pipeline
- Code splitting: Automatic chunking for optimal loading
- Tree shaking: Removes unused code in production
- Minification: Terser for JavaScript, CSS minification
- Fast Refresh: Sub-second HMR during development
Manual Optimizations
State Management
// Separate state variables for granular updates
const [showAppLauncher, setShowAppLauncher] = useState(false)
const [showProfileMenu, setShowProfileMenu] = useState(false)
// useRef for SDK instances (no re-renders)
const settings = useRef<any>(null)
// startTransition for batched updates
startTransition(() => {
setAppsList(apps)
setUserData(userData)
setSiteSettings(settings)
})Performance Metrics
| Metric | Value | Target | |--------|-------|--------| | Initial renders | 1 | < 3 | | Bundle size (gzipped) | ~150KB | < 200KB | | Time to Interactive | < 1s | < 2s | | First Contentful Paint | < 500ms | < 1s |
Best Practices
- Avoid unnecessary renders: Separate state variables
- Batch updates: Use
startTransitionfor multiple state changes - Stable references: Use
useReffor non-rendering data - Trust the compiler: Let React Compiler handle optimization
Browser Support
Modern browsers with ES2020+ support:
- Chrome/Edge 88+
- Firefox 78+
- Safari 14+
Project Structure
taruvi-navkit/
├── docs/
│ └── adr/ # Architecture Decision Records
│ └── 001-navkit-architecture.md
├── src/
│ ├── components/
│ │ ├── AppLauncher/
│ │ ├── Profile/
│ │ ├── Shortucts/
│ │ ├── Search/
│ │ └── MattermostChat/
│ ├── styles/
│ │ └── variables.ts # Design tokens
│ ├── NavkitContext.tsx # React Context provider & hook
│ ├── App.tsx # Main Navkit component
│ ├── App.styles.ts
│ └── types.ts # TypeScript interfaces
├── package.json
├── tsconfig.json
├── vite.config.ts
└── README.mdBuild Configuration
Vite
The project uses Vite 7 with:
- @vitejs/plugin-react for Fast Refresh
- babel-plugin-react-compiler for automatic optimizations
- HMR (Hot Module Replacement) enabled
- TypeScript support out of the box
TypeScript
Strict mode enabled with:
- noImplicitAny: Require explicit types
- strictNullChecks: Catch null/undefined errors
- esModuleInterop: Better module compatibility
Contributing
- Follow the existing code style
- Use TypeScript for all new files
- Add/update ADRs for architectural decisions
- Test responsive behavior on mobile and desktop
- Ensure no console errors or warnings
Troubleshooting
Common Issues
Navigation not working
Symptoms: Clicks don't navigate, URLs incorrect
Solutions:
- Ensure
frontendUrlis set in site settings for desk mode - Check that URLs are valid (full URLs or relative paths starting with
/) - Verify SDK settings instance is being passed correctly
- Check console for navigation errors
// Debug navigation
console.log('Settings:', await settings.get())
console.log('Is Desk?', await isDesk(settings))Styles not applying
Symptoms: Components look unstyled or broken
Solutions:
- Check that MUI is installed as a peer dependency:
npm list @mui/material - Verify design tokens are imported in component styles
- Ensure
sxprop is used (notstyle) - Check for CSS conflicts from parent app
# Verify MUI installation
npm list @mui/material @emotion/react @emotion/styledClick-outside not working
Symptoms: Menus don't close when clicking outside
Solutions:
- Check that menus have proper refs assigned
- Verify useEffect dependencies include all
show*states - Ensure no other click handlers are interfering with event propagation
- Check that
menuRefis attached to menu container
App launcher empty
Symptoms: No apps showing in launcher
Solutions:
- Verify
user.getApps()returns data - Check console for API errors
- Ensure apps have required fields:
id,appname,icon,url - Test with mock data to isolate issue
// Debug apps data
console.log('Apps:', await user.current.getApps())Icons not showing
Symptoms: Icons appear as boxes or missing
Solutions:
- Verify FontAwesome packages installed
- Check icon names match FontAwesome free icons
- Ensure
library.add(fas, far)is called - Use correct icon name format (without
fa-prefix)
// Debug icon
<FontAwesomeIcon icon={["fas", "envelope"]} /> // Correct
<FontAwesomeIcon icon={["fas", "fa-envelope"]} /> // WrongGetting Help
- Check the ADR documentation for architecture details
- Review existing ADRs for design decisions
- Enable verbose logging in development
- Contact the Taruvi development team for support
License
Internal Taruvi project - All rights reserved
Documentation
Architecture Decision Records (ADRs)
- Comprehensive ADR - Complete architectural decisions and rationale
- ADR 001: Navkit Architecture - Detailed component architecture
- Future Considerations - Planned enhancements
Key Documentation Sections
| Topic | Location | |-------|----------| | Technology stack decisions | adr.md - Tech Stack | | State management strategy | adr.md - State Management | | Navigation system | adr.md - Navigation System | | Responsive design | adr.md - Responsive Design | | Performance optimizations | adr.md - Performance | | Component architecture | docs/adr/001 |
External Resources
- React 19 Documentation
- Material-UI Documentation
- Vite Documentation
- TypeScript Handbook
- FontAwesome Icons
Support
For issues, questions, or feature requests, contact the Taruvi development team.
