# How Chat2DB Manages Its User Interface: React, Zustand, and Ant Design

> Discover how Chat2DB manages its user interface using React, Zustand state management, and Ant Design. Learn about UI state persistence for a smooth user experience. OtterMind/Chat2DB

- Repository: [OtterMind/Chat2DB](https://github.com/OtterMind/Chat2DB)
- Tags: architecture
- Published: 2026-07-27

---

**Chat2DB manages its user interface through a centralized Zustand store, React component hierarchy, and Ant Design theming, with all UI state persisted to local storage for a seamless cross-session experience.**

Chat2DB is an open-source database management tool built by OtterMind as a modern React single-page application. The **user interface** architecture combines the Umi framework for routing, Ant Design for components, and Zustand for state management. This setup allows the application to maintain consistent theming, resizable layouts, and synchronized navigation across database chat, BI visualization, and table editing features.

## Core Architecture of the Chat2DB User Interface

The interface follows a hierarchical component structure anchored by global layout containers and split-pane workspaces.

### Technology Stack and Framework

The frontend is built on **React** with **Umi** handling route-based code splitting. **Ant Design** provides the underlying UI components, while **Zustand** (via `useGlobalStore`) manages cross-cutting concerns like theme preferences, panel widths, and shortcut configurations. All user interface settings are automatically persisted to browser local storage using Zustand's persistence middleware.

### Layout Hierarchy

The top-level **`GlobalLayout`** component ([`chat2db-community-client/src/layouts/GlobalLayout/index.tsx`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-client/src/layouts/GlobalLayout/index.tsx)) wraps the entire application. It injects the Ant Design `ConfigProvider`, renders the custom `AppTheme` wrapper, and displays a loading state while checking backend service status. Routed content renders inside this layout via Umi's `<Outlet />`.

Beneath the global wrapper sits the **`Workspace`** component ([`chat2db-community-client/src/pages/main/workspace/index.tsx`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-client/src/pages/main/workspace/index.tsx)), which implements a resizable split-pane layout using `react-split-pane`. This divides the screen into left and right panels whose widths are synchronized with the workspace store.

## Global State Management for UI Consistency

All user interface state lives in a Zustand store defined in [`chat2db-community-client/src/store/global/store.ts`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-client/src/store/global/store.ts).

### Store Structure and Selectors

The store is organized into logical slices (`common`, `settings`, `request`, `misc`, `hotUpdate`). Components access UI settings through selectors like `settingSelectors.currentBaseSetting`, which extracts `primaryColor`, `appearance`, `customFont`, and `customFontSize`.

```tsx
import { useGlobalStore } from '@/store/global';
import { settingSelectors } from '@/store/global/selectors';

const { appearance, primaryColor } = useGlobalStore(state => ({
  ...settingSelectors.currentBaseSetting(state),
}));

```

### Persistence Strategy

UI preferences are persisted using `zustand/middleware` with a storage key defined by `runtimeEditionConfig.globalStoreName`. Only specific fields—`mainPageActiveTab`, `loginType`, `baseSetting`, and panel widths—are written to local storage, ensuring the user interface restores exactly as the user left it.

## Theming and Dynamic Layout Components

### AppTheme and Runtime Theming

The **`AppTheme`** component ([`chat2db-community-client/src/components/AppTheme/index.tsx`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-client/src/components/AppTheme/index.tsx)) wraps Ant Design's `ThemeProvider`. It reads the current theme configuration from the global store and applies `primaryColor`, `appearance` (dark/light), and `customFont` settings without requiring a page reload. This enables instant theme switching across the entire user interface.

### Resizable Workspace Panels

The workspace implements draggable splitters using `SplitPane`. Panel widths are stored in the workspace store ([`chat2db-community-client/src/store/workspace/store.ts`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-client/src/store/workspace/store.ts)) under `panelLeftWidth`. When users resize panels, the new dimensions propagate through the store and persist across sessions.

```tsx
import SplitPane from 'react-split-pane';
import { useWorkspaceStore } from '@/store/workspace';

const WorkspaceLayout = () => {
  const { panelLeftWidth, setPanelLeftWidth } = useWorkspaceStore(s => ({
    panelLeftWidth: s.layout.panelLeftWidth,
    setPanelLeftWidth: s.setPanelLeftWidth,
  }));
  const [size, setSize] = React.useState(panelLeftWidth);

  return (
    <SplitPane
      split="vertical"
      size={size}
      minSize={200}
      onChange={(newSize) => {
        setSize(newSize);
        setPanelLeftWidth(newSize);
      }}
    >
      <WorkspaceLeft />
      <WorkspaceRight />
    </SplitPane>
  );
};

```

### Theme Toggling Implementation

Components can modify the user interface theme by dispatching actions from the settings slice. This updates the global store and triggers a re-render of `AppTheme` with new Ant Design tokens.

```tsx
import { useGlobalStore } from '@/store/global';
import { settingActions } from '@/store/global/slices/settings/action';

const ThemeToggle = () => {
  const setAppearance = useGlobalStore(state => settingActions.setAppearance(state));
  const current = useGlobalStore(state => state.baseSetting.appearance);

  const toggle = () => {
    setAppearance(current.includes('dark') ? 'light' : 'dark');
  };

  return <Button onClick={toggle}>Toggle Theme</Button>;
};

```

## Feature Modules and Component Organization

Feature-specific user interface sections—such as **Chat**, **BI**, and **TableEditor**—are organized as lazy-loaded modules under `src/pages/main/`. Each module self-manages its internal state while consuming the global store for shared settings.

The chat interface ([`chat2db-community-client/src/pages/main/chat/index.tsx`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-client/src/pages/main/chat/index.tsx)) demonstrates this pattern: it renders `ChatHeader`, `ChatMessage`, and `ChatInput` components while accessing global theme settings and workspace configurations from Zustand. This modular approach allows the user interface to load features on demand while maintaining visual consistency.

## Summary

- **Chat2DB** builds its user interface as a React SPA using **Umi** for routing and **Ant Design** for component primitives.
- **Zustand** (`useGlobalStore`) centrally manages UI state including themes, fonts, and layout dimensions in [`chat2db-community-client/src/store/global/store.ts`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-client/src/store/global/store.ts).
- **GlobalLayout** and **Workspace** components provide the structural foundation with resizable split panes that persist their state via the workspace store.
- **AppTheme** enables runtime theme switching by reading from the global store and wrapping Ant Design's ThemeProvider.
- All user interface preferences are automatically persisted to local storage, ensuring a consistent experience across browser sessions.

## Frequently Asked Questions

### How does Chat2DB handle dark mode and custom themes?

Chat2DB implements runtime theme switching through the `AppTheme` component in [`chat2db-community-client/src/components/AppTheme/index.tsx`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-client/src/components/AppTheme/index.tsx). This component extracts `appearance`, `primaryColor`, and font settings from the Zustand global store and passes them to Ant Design's ThemeProvider. When users toggle themes via `settingActions.setAppearance`, the store updates instantly and the UI re-renders without reloading the page.

### Where is the user interface state stored in Chat2DB?

All global UI state resides in the Zustand store defined at [`chat2db-community-client/src/store/global/store.ts`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-client/src/store/global/store.ts). The store uses `zustand/persist` middleware to write specific fields—such as active tabs, theme preferences, and panel widths—to the browser's local storage under a key defined by `runtimeEditionConfig.globalStoreName`.

### How are the resizable panels in the Chat2DB workspace implemented?

The workspace uses `react-split-pane` inside [`chat2db-community-client/src/pages/main/workspace/index.tsx`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-client/src/pages/main/workspace/index.tsx). The splitter width is bound to `panelLeftWidth` in the workspace slice of the Zustand store ([`chat2db-community-client/src/store/workspace/store.ts`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-client/src/store/workspace/store.ts)). When users drag the splitter, the component calls `setPanelLeftWidth` to update the store, which both re-renders the UI and persists the new size for future sessions.

### What framework does Chat2DB use for routing and layout?

Chat2DB uses the **Umi** framework to handle routing and layout. The `GlobalLayout` component serves as the root layout wrapper in [`chat2db-community-client/src/layouts/GlobalLayout/index.tsx`](https://github.com/OtterMind/Chat2DB/blob/main/chat2db-community-client/src/layouts/GlobalLayout/index.tsx), rendering a `<Outlet />` where Umi injects route-matched components. This architecture enables code splitting and modular feature loading while maintaining consistent global UI elements like the title bar and theme provider.