# UI Shell

A comprehensive application shell framework providing theme management, feature flags, routing, and layout orchestration for microkernel-based applications.

## Package Structure

This is a monorepo package containing four sub-packages following the API-SPI-IMPL pattern:

- **[@hamak/ui-shell-api](./ui-shell-api)** - Type definitions, interfaces, and service tokens
- **[@hamak/ui-shell-spi](./ui-shell-spi)** - Service Provider Interfaces for extensibility
- **[@hamak/ui-shell-impl](./ui-shell-impl)** - Concrete implementations of all services
- **[@hamak/ui-shell-templates](./ui-shell-templates)** - React templates, components, and hooks

## Features

### Theme Management
- **Dynamic theme switching** between light, dark, and system modes
- **LocalStorage persistence** for user preferences
- **System preference detection** with automatic fallback
- **Custom CSS variables** support
- **Event-driven** theme change notifications

### Feature Configuration
- **Feature flags** for enabling/disabling functionality
- **Type-safe** feature access with generic types
- **Subscribe to feature changes** with fine-grained listeners
- **Bulk feature updates** for configuration management
- Includes **common feature definitions** for quick setup

### Router Integration
- **Lazy loading** support for route components
- **Navigation guards** for route protection
- **History and hash modes** for different deployment scenarios
- **Route metadata** for custom data attachment
- **Event-driven** navigation updates

### Layout Management
- **Slot-based layout system** with priority ordering
- **Responsive breakpoints** (xs, sm, md, lg, xl, 2xl)
- **Viewport utilities** for responsive behavior
- **CSS Grid layouts** with pre-built templates
- **Touch detection** and device pixel ratio utilities

### Microkernel Integration
- **Plugin module** for seamless microkernel integration
- **Dependency injection** tokens for all services
- **Command registration** for shell operations
- **Event forwarding** to microkernel hooks
- **Service providers** for easy consumption

## Installation

```bash
# Install the packages you need
bun add @hamak/ui-shell-api @hamak/ui-shell-impl @hamak/ui-shell-templates
```

## Usage

### Basic Shell Setup

```typescript
import { createShellPlugin } from '@hamak/ui-shell-impl';

const shellPlugin = createShellPlugin({
  theme: {
    mode: 'system', // 'light' | 'dark' | 'system'
    cssVariables: {
      '--primary-color': '#007bff',
    },
  },
  features: {
    'ui.sidebar': true,
    'experimental.ssr': false,
  },
});

// Register with your microkernel
kernel.registerPlugin(shellPlugin);
```

### Theme Management

```typescript
import { SHELL_TOKEN } from '@hamak/ui-shell-api';
import type { IShell } from '@hamak/ui-shell-api';

// In your plugin or component
const shell = context.resolve<IShell>(SHELL_TOKEN);
const themeManager = shell.getThemeManager();

// Set theme
themeManager.setTheme('dark');

// Toggle theme
themeManager.toggleTheme();

// Subscribe to changes
themeManager.subscribe((theme) => {
  console.log('Theme changed to:', theme);
});

// Get resolved theme (converts 'system' to actual theme)
const resolvedTheme = themeManager.getResolvedTheme(); // 'light' | 'dark'
```

### Feature Flags

```typescript
const featureManager = shell.getFeatureManager();

// Check if enabled
if (featureManager.isEnabled('ui.sidebar')) {
  // Show sidebar
}

// Get feature value
const pollingInterval = featureManager.get('performance.polling', 5000);

// Toggle feature
featureManager.toggle('experimental.ssr');

// Subscribe to changes
featureManager.subscribe('ui.sidebar', (enabled) => {
  console.log('Sidebar:', enabled ? 'enabled' : 'disabled');
});
```

### Router Setup

```typescript
import { SHELL_TOKEN } from '@hamak/ui-shell-api';

const shell = context.resolve(SHELL_TOKEN);
const router = shell.setupRouter({
  mode: 'history',
  routes: [
    {
      path: '/',
      component: () => import('./pages/Home'),
    },
    {
      path: '/about',
      component: () => import('./pages/About'),
      meta: { title: 'About Us' },
    },
    {
      path: '/dashboard',
      component: () => import('./pages/Dashboard'),
      beforeEnter: (to, from) => {
        // Route guard logic
        return isAuthenticated();
      },
    },
  ],
});

// Navigate
await router.push('/about');

// Subscribe to route changes
router.subscribe((route) => {
  console.log('Navigated to:', route.path);
});
```

### Contributed Routes and Store-fs Views

Plugins contribute routes and view resolvers through `createViewRoutingPlugin()`:

```typescript
import { ROUTE_REGISTRY_TOKEN, VIEW_RESOLVER_REGISTRY_TOKEN } from '@hamak/ui-shell';

// manifest: { name: 'studio', dependsOn: ['view-routing'], ... }
initialize(ctx) {
  ctx.resolve(ROUTE_REGISTRY_TOKEN).register({ path: '/content/*', component: ContentPage, plugin: 'studio' });
  ctx.resolve(VIEW_RESOLVER_REGISTRY_TOKEN).register({
    id: 'studio-model',
    priority: 10,
    resolve: (ref) => (ref.node.name.endsWith('.dm.json') ? ModelStudio : undefined),
  });
}
```

`<ContentView path fs />` (from `@hamak/ui-shell/react`) observes the store-fs node at `path` and renders the component
the highest-priority resolver returns, or a default view. It dispatches nothing; loading the node is the host's job.

**Which route type?** `RouteContribution` (the route registry) is for hosts that render routes with their own router,
such as react-router: read `useRouteContributions()` in the layout. `RouteConfig` is the table of the shell's built-in
`DefaultRouter` (lazy components, guards). Registrations are not removed when a plugin deactivates, so keep the
`dispose` handle if your plugin can be deactivated.

### Layout Management

```typescript
import { SHELL_TOKEN } from '@hamak/ui-shell-api';

const shell = context.resolve(SHELL_TOKEN);
const layoutManager = shell.getLayoutManager();

// Register slots
layoutManager.registerSlot({
  id: 'main-nav',
  area: 'header',
  priority: 10,
});

// Get slots for an area
const headerSlots = layoutManager.getSlots('header');

// Responsive utilities
if (ViewportUtils.isMinBreakpoint('md')) {
  // Desktop layout
} else {
  // Mobile layout
}

const currentBreakpoint = ViewportUtils.getCurrentBreakpoint();
```

### Microkernel Plugin Integration

```typescript
import { createShellPlugin } from '@hamak/ui-shell-impl';
import { CommonFeatures } from '@hamak/ui-shell-api';

export const shellPlugin = createShellPlugin({
  theme: { mode: 'system' },
  features: {
    'ui.sidebar': true,
  },
});

// In your plugin
export function initialize(ctx) {
  // Access shell services
  const shell = ctx.resolve(SHELL_TOKEN);

  // Subscribe to theme changes
  shell.getThemeManager().subscribe((theme) => {
    console.log('Theme changed:', theme);
  });
}

export function activate(ctx) {
  // Access shell services
  const shell = ctx.resolve(SHELL_TOKEN);
  shell.getThemeManager().setTheme('dark');
}
```

### Using React Templates

```typescript
import { ShellProvider, DashboardLayout } from '@hamak/ui-shell-templates';
import { useTheme, useFeatures } from '@hamak/ui-shell-templates/hooks';

// Wrap your app with ShellProvider
function App() {
  return (
    <ShellProvider>
      <DashboardLayout />
    </ShellProvider>
  );
}

// Use hooks in your components
function MyComponent() {
  const { theme, setTheme } = useTheme();
  const { isEnabled } = useFeatures();

  return (
    <div>
      <button onClick={() => setTheme('dark')}>Dark Mode</button>
      {isEnabled('ui.sidebar') && <Sidebar />}
    </div>
  );
}
```

### Shell Context

```typescript
import { SHELL_TOKEN } from '@hamak/ui-shell-api';

const shell = context.resolve(SHELL_TOKEN);
const shellContext = shell.getContext();

// Access current theme
console.log('Current theme:', shellContext.theme);

// Set theme
shellContext.setTheme('dark');

// Check features
if (shellContext.isFeatureEnabled('ui.sidebar')) {
  // ...
}

// Responsive info
if (shellContext.viewport.isMobile) {
  // Mobile UI
} else if (shellContext.viewport.isDesktop) {
  // Desktop UI
}
```

### Shell Events

```typescript
// Subscribe to events
shell.on('theme:changed', (event) => {
  console.log('Theme changed:', event.payload);
});

shell.on('viewport:resized', (event) => {
  console.log('Viewport:', event.payload.width, 'x', event.payload.height);
});

shell.on('route:changed', (event) => {
  console.log('Navigated to:', event.payload.route.path);
});

// Listen to all events
shell.on('*', (event) => {
  console.log('Event:', event.type, event.payload);
});
```

## API Reference

### Shell

Main orchestrator for the UI shell.

**Methods:**
- `initialize()` - Initialize the shell
- `setupRouter(options)` - Setup router with routes
- `getRouter()` - Get router instance
- `getThemeManager()` - Get theme manager
- `getFeatureManager()` - Get feature manager
- `getContext()` - Get shell context for consumers
- `on(type, listener)` - Subscribe to events
- `emit(type, payload)` - Emit events
- `destroy()` - Clean up resources

### ThemeManager

Handles theme switching and persistence.

**Methods:**
- `getTheme()` - Get current theme mode
- `getResolvedTheme()` - Get resolved theme (light/dark)
- `setTheme(mode)` - Set theme mode
- `toggleTheme()` - Toggle between light and dark
- `subscribe(listener)` - Subscribe to changes
- `setCSSVariables(vars)` - Set custom CSS variables

### FeatureManager

Manages feature flags and configurations.

**Methods:**
- `isEnabled(key)` - Check if feature is enabled
- `get(key, defaultValue)` - Get feature value
- `set(key, value)` - Set feature value
- `enable(key)` - Enable feature
- `disable(key)` - Disable feature
- `toggle(key)` - Toggle feature
- `subscribe(key, listener)` - Subscribe to feature changes

### Router

Handles client-side routing with lazy loading.

**Methods:**
- `push(path)` - Navigate to path
- `replace(path)` - Replace current route
- `back()` - Go back
- `forward()` - Go forward
- `getCurrentRoute()` - Get current route
- `subscribe(listener)` - Subscribe to route changes
- `addGuard(guard)` - Add navigation guard

### LayoutManager

Manages layout slots and areas.

**Methods:**
- `registerSlot(slot)` - Register a layout slot
- `unregisterSlot(slot)` - Unregister a slot
- `getSlots(area)` - Get slots for area
- `getAreas()` - Get all registered areas
- `hasSlots(area)` - Check if area has slots

## Architecture

The UI Shell is designed to integrate seamlessly with the microkernel architecture:

1. **Core Services**: Theme, Features, Router, Layout
2. **Plugin Integration**: Provides services via DI tokens
3. **Event System**: Forwards events to microkernel hooks
4. **Commands**: Registers shell commands for cross-plugin use
5. **Context API**: Provides reactive access to shell state

## Common Patterns

### Responsive Layouts

```typescript
import { useViewport } from '@hamak/ui-shell-templates/hooks';

// In React components
function MyComponent() {
  const { isMobile, isDesktop, breakpoint } = useViewport();

  return isMobile ? <MobileLayout /> : <DesktopLayout />;
}
```

### Feature Gating

```typescript
import { CommonFeatures } from '@hamak/ui-shell-api';
import { useFeatures } from '@hamak/ui-shell-templates/hooks';

function MyComponent() {
  const { isEnabled } = useFeatures();

  return (
    <div>
      {isEnabled(CommonFeatures.VOICE_MODE) && <VoiceInput />}
    </div>
  );
}
```

## License

MIT
