feat(ai): preview react flow modal

- Expand CLAUDE.md with detailed app/package structure
- Add full-screen flow chart preview modal to AIDisplayFlowPart
- Improve flow chart display and loading element sizing
This commit is contained in:
Innei 2025-08-07 19:21:13 +08:00
parent 9a12198d23
commit c654ca176c
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
3 changed files with 97 additions and 28 deletions

View File

@ -10,18 +10,37 @@ Follow (Folo) is a modern RSS aggregator and content management platform with mu
### Applications (`apps/`)
- **`apps/desktop/`** - Electron desktop application with main and renderer processes
- **`apps/desktop/`** - Electron desktop application
- `layer/main/` - Electron main process
- `layer/renderer/` - Vite + React renderer (primary web app)
- **`apps/mobile/`** - React Native mobile app for iOS and Android
- **`apps/ssr/`** - Server-side rendered web application
- **`apps/mobile/web-app/`** - HTML renderer for mobile web views
- `src/` - React Native source code
- `native/` - Native module implementations
- `web-app/` - HTML renderer for mobile web views
- `android/` - Android-specific configuration
- `ios/` - iOS-specific configuration
- **`apps/ssr/`** - Server-side rendered web application (minimal, for external sharing)
### Packages (`packages/`)
- **`packages/internal/`** - Internal shared packages (components, database, hooks, store, etc.)
- **`packages/configs/`** - Shared configuration files (Tailwind, TypeScript)
- **`packages/utils/`** - Utility functions and helpers
- **`packages/readability/`** - Content readability parsing
- **`packages/vite-plugin-route-builder/`** - Custom Vite plugin for route generation
- **`packages/internal/`** - Core shared packages
- `atoms/` - Jotai atomic state definitions
- `components/` - Shared UI components
- `constants/` - Application constants
- `database/` - Drizzle ORM database layer
- `hooks/` - Shared React hooks
- `models/` - Data models and schemas
- `shared/` - Cross-platform shared utilities
- `store/` - Zustand stores
- `types/` - TypeScript type definitions
- `utils/` - Utility functions and helpers
- `tracker/` - Analytics and tracking
- `logger/` - Logging utilities
- `legal/` - Legal and compliance utilities
- **`packages/configs/`** - Shared configuration files
- `tailwindcss/` - Tailwind CSS configurations
- TypeScript and build configurations
- **`packages/readability/`** - Content readability parsing and extraction
## Essential Commands
@ -69,19 +88,6 @@ pnpm run typecheck
pnpm run test
```
### Package Management
```bash
# Build shared packages
pnpm run build:packages
# Generate i18n templates
pnpm run generator:i18n-template
# Sync icons from SVG to React Native
pnpm run icons:sync
```
## Architecture Guidelines
### Multi-Platform Architecture

View File

@ -1,11 +1,46 @@
import "@xyflow/react/dist/style.css"
import { useIsDark } from "@follow/hooks"
import { Background, ReactFlow } from "@xyflow/react"
import { cn } from "@follow/utils/utils"
import { Background, Controls, ReactFlow } from "@xyflow/react"
import { useCallback } from "react"
import { useModalStack } from "~/components/ui/modal/stacked/hooks"
import type { AIDisplayFlowTool } from "../../store/types"
import { toolMemo } from "./share"
const FlowPreviewModal = ({
nodes,
edges,
colorMode,
}: {
nodes: any[]
edges: any[]
colorMode: "light" | "dark"
}) => {
return (
<div className="flex size-full flex-col">
<ReactFlow
colorMode={colorMode}
nodes={nodes}
edges={edges}
fitView
nodesDraggable={true}
nodesConnectable={false}
nodesFocusable={true}
edgesFocusable={true}
elementsSelectable={true}
preventScrolling={false}
className="size-full"
>
<Background />
<Controls />
</ReactFlow>
</div>
)
}
export const AIDisplayFlowPart = toolMemo(
({ part, loadingElement }: { part: AIDisplayFlowTool; loadingElement: React.ReactNode }) => {
if (!part.input) return loadingElement
@ -15,8 +50,22 @@ export const AIDisplayFlowPart = toolMemo(
const { nodes, edges } = part.input.flowChart as any
const colorMode = useIsDark() ? "dark" : "light"
const { present } = useModalStack()
const handleOpenModal = useCallback(() => {
present({
title: "Flow Chart Preview",
content: () => <FlowPreviewModal nodes={nodes} edges={edges} colorMode={colorMode} />,
max: true,
canClose: true,
clickOutsideToDismiss: false,
modalContentClassName: "p-0 h-full",
modalClassName: "h-[90vh] w-[90vw]",
})
}, [nodes, edges, colorMode, present])
return (
<div className="my-2 aspect-[4/3] w-full overflow-hidden rounded-md">
<div className="group relative my-2 aspect-[4/3] w-[99999999px] max-w-full overflow-hidden rounded-md">
<ReactFlow
colorMode={colorMode}
nodes={nodes}
@ -27,14 +76,28 @@ export const AIDisplayFlowPart = toolMemo(
nodesFocusable={false}
edgesFocusable={false}
elementsSelectable={false}
panOnDrag={false}
zoomOnScroll={false}
zoomOnPinch={false}
zoomOnDoubleClick={false}
preventScrolling={false}
>
<Background />
<Controls />
</ReactFlow>
{/* Expand/Preview button */}
<button
type="button"
onClick={handleOpenModal}
className={cn(
"absolute right-2 top-2 flex items-center gap-1.5 rounded-lg px-2.5 py-1.5",
"bg-material-thick text-text-secondary text-sm font-medium",
"opacity-0 transition-all duration-200 group-hover:opacity-100",
"hover:bg-material-medium hover:text-text focus:opacity-100",
"focus:ring-blue focus:outline-none focus:ring-2 focus:ring-offset-1",
)}
title="Open in full screen"
>
<i className="i-mgc-external-link-cute-re size-4" />
<span>Preview</span>
</button>
</div>
)
},

View File

@ -108,7 +108,7 @@ export const AIMessageParts: React.FC<MessagePartsProps> = React.memo(({ message
case "tool-displayFlowChart": {
const loadingElement = (
<div className="my-2 flex aspect-[4/3] w-full items-center justify-center">
<div className="my-2 flex aspect-[4/3] w-[99999999px] max-w-full items-center justify-center">
<div className="flex flex-col items-center gap-4">
<div className="flex items-center gap-2">
<i className="i-mgc-loading-3-cute-re text-text-secondary size-4 animate-spin" />