Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion NOTICE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Sim Studio
Copyright 2026 Sim Studio

This product includes software developed for the Sim project.
This product includes software developed for the Sim project.
3 changes: 2 additions & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@
"@sim/tsconfig": "workspace:*",
"@types/micromatch": "4.0.10",
"@types/node": "24.2.1",
"electron": "43.5.0",
"electron": "43.4.1",
"electron-builder": "26.15.3",
"esbuild": "0.28.1",
"jsdom": "^26.0.0",
"typescript": "^7.0.2",
"vitest": "^4.1.0"
}
Expand Down
25 changes: 15 additions & 10 deletions apps/docs/app/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ body {
nominally references; loading a webfont here would make docs the odd one out, not the
aligned one. If the app ever wires that font up for real, add the var back in both
places at once. */
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace;
--font-mono:
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
monospace;
Comment thread
waleedlatif1 marked this conversation as resolved.
}

/* Pure white light mode background */
Expand Down Expand Up @@ -243,14 +244,16 @@ body {

/* Font family utilities */
.font-sans {
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-family:
var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "Helvetica Neue", Arial, sans-serif;
}

/* Platform UI font — Season Sans, used by the chip chrome to match the main app */
.font-season {
font-family: var(--font-season), system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial,
"Noto Sans", sans-serif;
font-family:
var(--font-season), system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans",
sans-serif;
}

:root {
Expand Down Expand Up @@ -445,8 +448,9 @@ html #nd-sidebar button:not([aria-label*="ollapse"]):not([aria-label*="xpand"])
padding: 5px 0.5rem !important; /* 30px tall overall — the app's chip pill, at its px-2 */
font-weight: 400 !important;
border-radius: 0.5rem !important; /* platform rounded-lg */
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
font-family:
var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "Helvetica Neue", Arial, sans-serif !important;
}

/* Sidebar text — platform --text-body */
Expand Down Expand Up @@ -904,8 +908,9 @@ video {
#nd-page:has(.api-page-header) div:not(.font-mono),
#nd-page:has(.api-page-header) label:not(.font-mono),
#nd-page:has(.api-page-header) button:not(.font-mono) {
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-family:
var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "Helvetica Neue", Arial, sans-serif;
}

/* Method badge pills — shared background colors (page + sidebar) */
Expand Down
6 changes: 3 additions & 3 deletions apps/docs/components/workflow-preview/block-preview.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
'use client'

import { useMemo } from 'react'
import { type NodeTypes, ReactFlow, ReactFlowProvider } from '@xyflow/react'
import { domAnimation, LazyMotion } from 'framer-motion'
import ReactFlow, { type NodeTypes, ReactFlowProvider } from 'reactflow'
import 'reactflow/dist/style.css'
import '@xyflow/react/dist/style.css'
import { BLOCK_DISPLAY_WORKFLOWS } from '@/components/workflow-preview/block-display-workflows'
import { DocsBlockNode } from '@/components/workflow-preview/docs-block-node'
import { toReactFlowElements } from '@/components/workflow-preview/workflow-data'

/** The hero mounts the same node type the canvas uses, so it can never drift. */
const NODE_TYPES: NodeTypes = { previewBlock: DocsBlockNode }
const NODE_TYPES = { previewBlock: DocsBlockNode } satisfies NodeTypes
const PRO_OPTIONS = { hideAttribution: true }
/** `maxZoom` mirrors the previous hand-rolled hero's 1.3 scale. */
const FIT_VIEW_OPTIONS = { padding: 0.2, maxZoom: 1.3 } as const
Expand Down
11 changes: 8 additions & 3 deletions apps/docs/components/workflow-preview/docs-block-node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import { type ComponentType, memo } from 'react'
import { SubBlockRowView, WorkflowBlockView } from '@sim/workflow-renderer'
import type { Node, NodeProps } from '@xyflow/react'
import { m } from 'framer-motion'
import type { NodeProps } from 'reactflow'
import { resolveIcon } from '@/components/workflow-preview/block-icons'
import {
BLOCK_STAGGER,
Expand All @@ -16,7 +16,7 @@ const EMPTY_ICON: ComponentType<{ className?: string }> = () => null

const RING_STYLES = 'ring-[1.75px] ring-[var(--brand-secondary)]'

interface DocsBlockData {
export interface DocsBlockData extends Record<string, unknown> {
name: string
blockType: string
bgColor: string
Expand All @@ -30,6 +30,8 @@ interface DocsBlockData {
isDimmed?: boolean
}

export type DocsBlockNodeType = Node<DocsBlockData, 'previewBlock'>

/**
* Docs adapter for workflow block nodes: maps the static preview data to the
* shared {@link WorkflowBlockView}'s props. Carries no stores, hooks, or
Expand All @@ -38,7 +40,10 @@ interface DocsBlockData {
* `WorkflowPreview` provides the `LazyMotion` feature set). The block's ring is
* driven by `hasRing`/`ringStyles` inside the View.
*/
export const DocsBlockNode = memo(function DocsBlockNode({ id, data }: NodeProps<DocsBlockData>) {
export const DocsBlockNode = memo(function DocsBlockNode({
id,
data,
}: NodeProps<DocsBlockNodeType>) {
const {
name,
blockType,
Expand Down
8 changes: 5 additions & 3 deletions apps/docs/components/workflow-preview/docs-container-node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@

import { memo } from 'react'
import { type SubflowNodeData, SubflowNodeView } from '@sim/workflow-renderer'
import type { NodeProps } from 'reactflow'
import type { Node, NodeProps } from '@xyflow/react'

interface DocsContainerData {
export interface DocsContainerData extends Record<string, unknown> {
name: string
blockType: string
size?: { width: number; height: number }
parentId?: string
}

export type DocsContainerNodeType = Node<DocsContainerData, 'previewContainer'>

/**
* Docs adapter for loop/parallel container blocks: maps the static preview data
* to {@link SubflowNodeView}'s read-only `isPreview` shape. Carries no stores,
Expand All @@ -19,7 +21,7 @@ interface DocsContainerData {
export const DocsContainerNode = memo(function DocsContainerNode({
id,
data,
}: NodeProps<DocsContainerData>) {
}: NodeProps<DocsContainerNodeType>) {
const subflowData: SubflowNodeData = {
kind: data.blockType === 'parallel' ? 'parallel' : 'loop',
name: data.name,
Expand Down
71 changes: 58 additions & 13 deletions apps/docs/components/workflow-preview/workflow-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@ import {
getEdgeZIndex,
getEdgeZIndexForTarget,
} from '@sim/workflow-renderer'
import { type Edge, type Node, Position } from 'reactflow'
import { type Edge, Position } from '@xyflow/react'
import type {
DocsBlockData,
DocsBlockNodeType,
} from '@/components/workflow-preview/docs-block-node'
import type {
DocsContainerData,
DocsContainerNodeType,
} from '@/components/workflow-preview/docs-container-node'

/**
* Tool entry displayed as a chip on a block (e.g. an Agent's attached tools).
Expand Down Expand Up @@ -51,6 +59,15 @@ export interface PreviewWorkflow {
edges: Array<{ id: string; source: string; target: string; sourceHandle?: string }>
}

export type PreviewNode = DocsBlockNodeType | DocsContainerNodeType

export interface PreviewEdgeData extends Record<string, unknown> {
animate: boolean
delay: number
}

export type PreviewFlowEdge = Edge<PreviewEdgeData, 'previewEdge'>

export const BLOCK_STAGGER = 0.12
export const EASE_OUT: [number, number, number, number] = [0.16, 1, 0.3, 1]

Expand Down Expand Up @@ -96,14 +113,14 @@ export function toReactFlowElements(
workflow: PreviewWorkflow,
animate = false,
highlight: HighlightOptions = {}
): { nodes: Node[]; edges: Edge[] } {
): { nodes: PreviewNode[]; edges: PreviewFlowEdge[] } {
const { highlightBlock, highlightEdge, selectedBlock } = highlight
const hasHighlight = Boolean(highlightBlock || highlightEdge)
const blockIndexMap = new Map(workflow.blocks.map((b, i) => [b.id, i]))

const blocksById = new Map(workflow.blocks.map((b) => [b.id, b]))

const nodes: Node[] = workflow.blocks.map((block, index) => {
const nodes: PreviewNode[] = workflow.blocks.map((block, index) => {
const isContainer = Boolean(block.size)
const nestingDepth = getNestingDepth(block, blocksById)
// Nested blocks are authored relative to their container; render them at
Expand All @@ -113,13 +130,20 @@ export function toReactFlowElements(
const position = parent
? { x: parent.position.x + block.position.x, y: parent.position.y + block.position.y }
: block.position
return {
const commonNode = {
id: block.id,
type: isContainer ? 'previewContainer' : 'previewBlock',
position,
zIndex: isContainer ? nestingDepth : block.parentId ? CONTAINER_CHILD_Z_BASE : BLOCK_Z_BASE,
...(block.size ? { style: { width: block.size.width, height: block.size.height } } : {}),
data: {
draggable: true,
selectable: false,
connectable: false,
sourcePosition: Position.Right,
targetPosition: Position.Left,
}

if (isContainer) {
const data: DocsContainerData = {
name: block.name,
blockType: block.type,
bgColor: block.bgColor,
Expand All @@ -133,16 +157,37 @@ export function toReactFlowElements(
animate,
isHighlighted: highlightBlock === block.id || selectedBlock === block.id,
isDimmed: hasHighlight && highlightBlock !== block.id,
},
draggable: true,
selectable: false,
connectable: false,
sourcePosition: Position.Right,
targetPosition: Position.Left,
}
return {
...commonNode,
type: 'previewContainer',
data,
}
}

const data: DocsBlockData = {
name: block.name,
blockType: block.type,
bgColor: block.bgColor,
rows: block.rows,
branches: block.branches,
tools: block.tools,
hideTargetHandle: block.hideTargetHandle,
size: block.size,
parentId: block.parentId,
index,
animate,
isHighlighted: highlightBlock === block.id || selectedBlock === block.id,
isDimmed: hasHighlight && highlightBlock !== block.id,
}
return {
...commonNode,
type: 'previewBlock',
data,
}
})

const edges: Edge[] = workflow.edges.map((e) => {
const edges: PreviewFlowEdge[] = workflow.edges.map((e) => {
const sourceIndex = blockIndexMap.get(e.source) ?? 0
const isEdgeHighlight = highlightEdge === e.id
const dimmed = hasHighlight && !isEdgeHighlight
Expand Down
31 changes: 16 additions & 15 deletions apps/docs/components/workflow-preview/workflow-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,29 @@

import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Expand, X } from '@sim/emcn/icons'
import { domAnimation, LazyMotion, m } from 'framer-motion'
import ReactFlow, {
import {
applyEdgeChanges,
applyNodeChanges,
type Edge,
type EdgeProps,
type EdgeTypes,
getSmoothStepPath,
type Node,
type NodeTypes,
type OnEdgesChange,
type OnNodesChange,
ReactFlow,
ReactFlowProvider,
} from 'reactflow'
import 'reactflow/dist/style.css'
} from '@xyflow/react'
import { domAnimation, LazyMotion, m } from 'framer-motion'
import '@xyflow/react/dist/style.css'
import { BLOCK_DISPLAY_WORKFLOWS } from '@/components/workflow-preview/block-display-workflows'
import { BlockInspector } from '@/components/workflow-preview/block-inspector'
import { DocsBlockNode } from '@/components/workflow-preview/docs-block-node'
import { DocsContainerNode } from '@/components/workflow-preview/docs-container-node'
import {
EASE_OUT,
type PreviewBlock,
type PreviewFlowEdge,
type PreviewNode,
type PreviewWorkflow,
toReactFlowElements,
} from '@/components/workflow-preview/workflow-data'
Expand All @@ -50,7 +51,7 @@ function PreviewEdge({
targetPosition,
style,
data,
}: EdgeProps) {
}: EdgeProps<PreviewFlowEdge>) {
const [edgePath] = getSmoothStepPath({
sourceX,
sourceY,
Expand Down Expand Up @@ -89,11 +90,11 @@ function PreviewEdge({
)
}

const NODE_TYPES: NodeTypes = {
const NODE_TYPES = {
previewBlock: DocsBlockNode,
previewContainer: DocsContainerNode,
}
const EDGE_TYPES: EdgeTypes = { previewEdge: PreviewEdge }
} satisfies NodeTypes
const EDGE_TYPES = { previewEdge: PreviewEdge } satisfies EdgeTypes
const PRO_OPTIONS = { hideAttribution: true }
const FIT_VIEW_OPTIONS = { padding: 0.25, maxZoom: 1 } as const
const LIGHTBOX_FIT_VIEW_OPTIONS = { padding: 0.3, maxZoom: 1.4 } as const
Expand Down Expand Up @@ -176,8 +177,8 @@ function PreviewFlow({
[workflow, animate, highlightBlock, highlightEdge, selectedBlock]
)

const [nodes, setNodes] = useState<Node[]>(initialNodes)
const [edges, setEdges] = useState<Edge[]>(initialEdges)
const [nodes, setNodes] = useState<PreviewNode[]>(initialNodes)
const [edges, setEdges] = useState<PreviewFlowEdge[]>(initialEdges)

/**
* Apply data changes (highlight/selection) without discarding positions the
Expand All @@ -194,17 +195,17 @@ function PreviewFlow({
setEdges(initialEdges)
}, [initialNodes, initialEdges])

const onNodesChange: OnNodesChange = useCallback(
const onNodesChange: OnNodesChange<PreviewNode> = useCallback(
(changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
[]
)
const onEdgesChange: OnEdgesChange = useCallback(
const onEdgesChange: OnEdgesChange<PreviewFlowEdge> = useCallback(
(changes) => setEdges((eds) => applyEdgeChanges(changes, eds)),
[]
)

return (
<ReactFlow
<ReactFlow<PreviewNode, PreviewFlowEdge>
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@sim/db": "workspace:*",
"@sim/emcn": "workspace:*",
"@sim/workflow-renderer": "workspace:*",
"@xyflow/react": "12.11.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"drizzle-orm": "^0.45.2",
Expand All @@ -35,7 +36,6 @@
"remark-breaks": "^4.0.0",
"shiki": "4.3.1",
"tailwind-merge": "^3.0.2",
"reactflow": "^11.11.4",
"framer-motion": "^12.5.0",
"zod": "4.3.6"
},
Expand Down
Loading
Loading