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:
parent
9a12198d23
commit
c654ca176c
48
CLAUDE.md
48
CLAUDE.md
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
Loading…
Reference in New Issue